首页
/ Material UI Divider 完全指南:变体、垂直分隔线、嵌入文本与可访问性实践

Material UI Divider 完全指南:变体、垂直分隔线、嵌入文本与可访问性实践

2026-09-06 11:24:34作者:韦蓉瑛

Material UI 的 Divider 组件用一条纤细、不抢眼的线条将内容分组,从而强化页面的视觉层级。本文基于仓库中的官方文档 dividers.md 与组件源码 Divider.js,系统讲解它的三种变体、水平/垂直方向、flex 布局适配、文本嵌入写法以及可访问性(ARIA)处理策略。读完后你将掌握 Divider 的全部 Props、默认值与渲染元素规则,并能在列表、工具栏图标分组、卡片分区等真实场景中使用它。

基础引入与默认渲染

引入方式很简单,支持按路径独立导入,有助于打包器做 tree-shaking:

import Divider from '@mui/material/Divider';

Divider 默认渲染为一条深灰色的 <hr> 元素,并附带几个常用的 Props 供快速调整样式。其 DOM 结构如下(见官方文档 Anatomy 一节):

<hr class="MuiDivider-root">
  <!-- Divider children goes here -->
</hr>

源码 Divider.js 中,根节点的基础样式为:

{
  margin: 0, // Reset browser default style.
  flexShrink: 0,
  borderWidth: 0,
  borderStyle: 'solid',
  borderColor: (theme.vars || theme).palette.divider,
  borderBottomWidth: 'thin',
}

可以看到:分隔线的颜色取自主题中的 palette.divider(即"深灰色"的来源),同时重置了浏览器 <hr> 的默认外边距。官方示例 IntroDivider.tsx 展示了在 Card 内用 <Divider /> 分隔商品标题区与操作区的最常见用法。

Props 一览

综合 Divider.js 中的默认值与 PropTypes 定义:

Prop 类型 默认值 说明
absolute boolean false 绝对定位到父容器底部
children ReactNode 包裹在分隔线中的文本/图标等节点
className string 附加根节点类名
component ElementType 动态计算 根节点使用的元素,详见下文
flexItem boolean false 用于 flex 容器中的正确高度
orientation 'horizontal' | 'vertical' 'horizontal' 分隔线方向
role string 动态计算 ARIA 角色,详见可访问性一节
textAlign 'center' | 'left' | 'right' 'center' 嵌入内容的对齐方式
variant 'fullWidth' | 'inset' | 'middle' 'fullWidth' 分隔线变体
sx object / array / function 系统样式 prop

其中 componentrole 的默认值由源码动态推导(Divider.js):

component = children || orientation === 'vertical' ? 'div' : 'hr',
role = component !== 'hr' ? 'separator' : undefined,

即:只要分隔线有子节点或处于垂直方向,根元素就自动从 <hr> 切换为 <div>,并补上 separator 角色——这正是它遵守 WAI-ARIA 分隔符(separator)规范的核心机制,后文会详述。

三种 variant 变体

Divider 支持 fullWidth(默认)、insetmiddle 三种变体,各自对应的样式在源码中通过 variants 定义:

variant 视觉效果 源码样式(Divider.js
fullWidth 贯穿整个容器宽度 无额外样式(默认 borderBottomWidth: 'thin'
inset 左侧内缩,常用于列表右侧对齐场景 marginLeft: 72
middle 两端留出间隙 水平方向:marginLeft/Right: theme.spacing(2)(即 16px);垂直方向:marginTop/Bottom: theme.spacing(1)(即 8px)

middle 的间距值在测试 Divider.test.js 中有精确断言:水平时计算样式为 16px,垂直时上下各 8px

官方示例 DividerVariants.tsxList 中并排演示了三种变体:

import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import Divider from '@mui/material/Divider';

export default function DividerVariants() {
  return (
    <List sx={style}>
      <ListItem>
        <ListItemText primary="Full width variant below" />
      </ListItem>
      <Divider component="li" />
      <ListItem>
        <ListItemText primary="Inset variant below" />
      </ListItem>
      <Divider variant="inset" component="li" />
      <ListItem>
        <ListItemText primary="Middle variant below" />
      </ListItem>
      <Divider variant="middle" component="li" />
      <ListItem>
        <ListItemText primary="List item" />
      </ListItem>
    </List>
  );
}

注意示例中每个 Divider 都带 component="li",原因在于下一节"与 List 搭配使用"中说明。

此外还有一个未在变体之列但同样重要的 prop:absolute。它在源码中对应(Divider.js):

{
  position: 'absolute',
  bottom: 0,
  left: 0,
  width: '100%',
}

适合把分隔线钉在父容器底边,例如卡片底部。

orientation:从水平到垂直

orientation prop 用于把分隔线从水平改为垂直。官方文档指出:使用垂直方向时,Divider 会渲染带相应可访问性属性的 <div>,而不是 <hr>,以遵守 WAI-ARIA 规范。这一点与源码中的默认值推导一致——orientation === 'vertical'component 自动落到 'div'

垂直方向的样式差异(Divider.js):

{
  height: '100%',
  borderBottomWidth: 0,
  borderRightWidth: 'thin',  // 线条从下边框换到右边框
}

同时 aria-orientation 属性的输出条件为(Divider.js):

aria-orientation={
  role === 'separator' && (component !== 'hr' || orientation === 'vertical')
    ? orientation
    : undefined
}

即只有当元素承担了 separator 角色且不是"纯 <hr> 水平分隔线"时才输出 aria-orientation,避免给 <hr> 冗余地叠加隐式语义(这一点被测试 "avoids adding implicit aria semantics" 明确验证,见 Divider.test.js)。

官方示例 VerticalDividers.tsx 展示了在工具栏中用垂直分隔线隔开两组图标:

<Box
  sx={{
    display: 'flex',
    alignItems: 'center',
    /* ... 容器样式 ... */
    [`& .${dividerClasses.root}`]: { mx: 0.5 },
  }}
>
  <FormatAlignLeftIcon />
  <FormatAlignCenterIcon />
  <FormatAlignRightIcon />
  <Divider orientation="vertical" flexItem />
  <FormatBoldIcon />
</Box>

这里用到了具名导出的 dividerClasses(在 index.d.ts 中导出),可以通过 dividerClasses.root 精确选中根节点类名做外层样式调整。

flexItem:flex 容器中的高度问题

垂直分隔线作为 flex 容器子项时,默认的 height: 100% 可能计算为 0pxflexItem prop 就是为解决此问题而设,其样式为(Divider.js):

{
  alignSelf: 'stretch',
  height: 'auto',
}

官方示例 FlexDivider.tsx 完整代码:

import FormatBoldIcon from '@mui/icons-material/FormatBold';
import FormatItalicIcon from '@mui/icons-material/FormatItalic';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';

export default function FlexDivider() {
  return (
    <Box
      sx={{
        display: 'inline-flex',
        alignItems: 'center',
        /* ... 容器边框背景等样式 ... */
        '& svg': { m: 1 },
      }}
    >
      <FormatBoldIcon />
      <Divider orientation="vertical" variant="middle" flexItem />
      <FormatItalicIcon />
    </Box>
  );
}

variant="middle" 让垂直线上下各留 spacing(1) 的间隙,flexItem 保证它撑满工具栏高度,两者组合即典型的"图标工具栏分隔"形态。

带 children:在分隔线中嵌入文本或 Chip

Divider 传入 children 后,根元素自动变为 <div>(见前文 component 默认值推导),内容被包裹进一个 spanDividerWrapper),而分隔线本身改由 ::before::after 伪元素绘制。核心样式(Divider.js):

// 有 children 时
{
  display: 'flex',
  textAlign: 'center',
  border: 0,
  borderTopStyle: 'solid',
  borderLeftStyle: 'solid',
  '&::before, &::after': {
    content: '""',
    alignSelf: 'center',
  },
}

// 水平方向:伪元素画上下两条水平线
'&::before, &::after': {
  width: '100%',
  borderTop: `thin solid ${(theme.vars || theme).palette.divider}`,
  borderTopStyle: 'inherit',
}

// 垂直方向:改画左右两条垂直线
'&::before, &::after': {
  height: '100%',
  borderLeft: `thin solid ${(theme.vars || theme).palette.divider}`,
  borderLeftStyle: 'inherit',
}

由于线条走的是伪元素的 border-top-style: inherit(垂直方向为 border-left-style: inherit),用 styledsx 覆盖 borderStyle(如改为 dashed)即可让伪元素线条同步生效——测试 "custom border style"(Divider.test.js)专门验证了这一继承行为。

textAlign 对齐

textAlign prop 控制嵌入内容的水平位置(默认 center,仅对水平方向有效)。实现方式是调节两条伪元素线段的宽度(Divider.js):

textAlign ::before 宽度 ::after 宽度
center(默认) 100% 100%
left 10% 90%
right 90% 10%

源码中 textAlignLeft / textAlignRight 类只在 orientation !== 'vertical' 时才附加(Divider.js),测试 "should not set the textAlignRight class if orientation='vertical'" 对此有明确断言。

官方示例 DividerText.tsx 演示了居中、左对齐、右对齐及嵌入 Chip 的完整形态:

<Divider>CENTER</Divider>
<Divider textAlign="left">LEFT</Divider>
<Divider textAlign="right">RIGHT</Divider>
<Divider>
  <Chip label="Chip" size="small" />
</Divider>

wrapper 节点(span)自带 whiteSpace: 'nowrap' 和基于 theme.spacing(1) * 1.2 的内边距,垂直方向时内边距换到上下方向,保证文本不会被线条压住。

定制与组合场景

与 List 搭配使用

List 中用 Divider 分隔条目时,必须通过 component prop 把它渲染为 <li>,否则 <hr> 出现在 <ul> 内不是合法的 HTML 结构。官方示例 ListDividers.tsx

<List sx={style} aria-label="mailbox folders">
  <ListItem>
    <ListItemText primary="Inbox" />
  </ListItem>
  <Divider component="li" />
  <ListItem>
    <ListItemText primary="Drafts" />
  </ListItem>
  {/* ... 其余条目与 Divider 结构相同 ... */}
</List>

渲染为 <li>component !== 'hr',组件会自动补上 role="separator"aria-orientation,语义依然完整(测试 "adds a proper role if none is specified" 验证了该行为,见 Divider.test.js)。

图标分组(垂直 middle)

variant="middle"orientation="vertical" 组合,可以在图标工具栏中制造一个带上下留白的分隔段。官方示例 VerticalDividerMiddle.tsx

<Card
  variant="outlined"
  sx={{
    display: 'flex',
    color: 'text.secondary',
    '& svg': { m: 1 },
    [`& .${dividerClasses.root}`]: { mx: 0.5 },
  }}
>
  <FormatAlignLeftIcon />
  <FormatAlignCenterIcon />
  <FormatAlignRightIcon />
  <Divider orientation="vertical" variant="middle" flexItem />
  <FormatBoldIcon />
</Card>

样式覆盖与全局默认值

  • 通过 dividerClasses 选择器或 overrides: { MuiDivider: { root / inset / middle / vertical / flexItem / withChildren / ... } } 主题 API 可覆盖任意槽位样式,各工具类名与条件一一对应,定义见 dividerClasses.tsrootabsolutefullWidthinsetmiddleverticalflexItemwithChildrentextAlignRighttextAlignLeftwrapperwrapperVertical
  • 组件内部通过 useDefaultProps({ props: inProps, name: 'MuiDivider' }) 读取 DefaultPropsProvider 注入的全局默认 props(Divider.js),因此可以为应用内所有 Divider 统一设置默认值(如全局 flexItemorientation)。
  • 所有颜色均来自 theme.palette.divider,自定义主题色只需改这一处,水平/垂直、有无 children 的伪元素线条都会跟随变化。

可访问性(Accessibility)

由于 <hr> 的隐式角色是 separator,默认水平的 Divider 会被屏幕阅读器朗读为 "Horizontal Splitter"(使用 orientation="vertical" 时则为 Vertical)。官方文档给出两条实用建议:

1. 纯装饰用途:让屏幕阅读器直接跳过

<Divider aria-hidden="true" />

2. 包裹其他元素(文本、Chip 等):改为普通 div 并声明 presentation 角色

<Divider component="div" role="presentation">
  <Typography>Text element</Typography>
</Divider>

这样屏幕阅读器不会朗读分隔线本身,但其中包裹元素的语义得以保留。

源码侧对 role 的处理策略与测试用例(Divider.test.js)共同确认了四个行为:

  1. 默认 <hr> 水平分隔线不额外输出 rolearia-orientation(避免叠加隐式语义);
  2. 显式 component="div" 且未指定 role 时,自动补 role="separator"aria-orientation
  3. orientation="vertical" 时同样自动补齐 ARIA 属性;
  4. 用户显式传入的 role(如 presentation)优先级最高,会覆盖推导值,且不再输出 aria-orientation

小结

Divider 的 API 表面简洁(约 10 个 props),但默认值逻辑相当讲究:componentrole 会依据 childrenorientation 动态推导,垂直方向与带文本场景自动切换到 <div> + separator 的 ARIA 合规形态;variantflexItemtextAlign 则分别解决内缩/留白、flex 高度、内容对齐三类布局问题。掌握 Divider.js 中"元素推导 → 工具类组装(dividerClasses.ts)→ 主题变体样式"这条链路,再配合 Divider.test.js 中的行为断言,即可在列表、工具栏、卡片等场景中准确、无障碍地使用它。

登录后查看全文
热门项目推荐
相关项目推荐