Material UI Divider 完全指南:变体、垂直分隔线、嵌入文本与可访问性实践
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 |
其中 component 与 role 的默认值由源码动态推导(Divider.js):
component = children || orientation === 'vertical' ? 'div' : 'hr',
role = component !== 'hr' ? 'separator' : undefined,
即:只要分隔线有子节点或处于垂直方向,根元素就自动从 <hr> 切换为 <div>,并补上 separator 角色——这正是它遵守 WAI-ARIA 分隔符(separator)规范的核心机制,后文会详述。
三种 variant 变体
Divider 支持 fullWidth(默认)、inset、middle 三种变体,各自对应的样式在源码中通过 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.tsx 在 List 中并排演示了三种变体:
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% 可能计算为 0px。flexItem 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 默认值推导),内容被包裹进一个 span(DividerWrapper),而分隔线本身改由 ::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),用 styled 或 sx 覆盖 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.ts:root、absolute、fullWidth、inset、middle、vertical、flexItem、withChildren、textAlignRight、textAlignLeft、wrapper、wrapperVertical。 - 组件内部通过
useDefaultProps({ props: inProps, name: 'MuiDivider' })读取DefaultPropsProvider注入的全局默认 props(Divider.js),因此可以为应用内所有Divider统一设置默认值(如全局flexItem或orientation)。 - 所有颜色均来自
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)共同确认了四个行为:
- 默认
<hr>水平分隔线不额外输出role与aria-orientation(避免叠加隐式语义); - 显式
component="div"且未指定 role 时,自动补role="separator"与aria-orientation; orientation="vertical"时同样自动补齐 ARIA 属性;- 用户显式传入的
role(如presentation)优先级最高,会覆盖推导值,且不再输出aria-orientation。
小结
Divider 的 API 表面简洁(约 10 个 props),但默认值逻辑相当讲究:component 与 role 会依据 children、orientation 动态推导,垂直方向与带文本场景自动切换到 <div> + separator 的 ARIA 合规形态;variant、flexItem、textAlign 则分别解决内缩/留白、flex 高度、内容对齐三类布局问题。掌握 Divider.js 中"元素推导 → 工具类组装(dividerClasses.ts)→ 主题变体样式"这条链路,再配合 Divider.test.js 中的行为断言,即可在列表、工具栏、卡片等场景中准确、无障碍地使用它。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00