Material UI System 排版工具指南:借助 sx 与 theme.typography 精细控制文本样式
本文基于 MUI 仓库
docs/data/system/typography/typography.md文档,围绕@mui/system提供的 Typography 排版工具函数展开。这套工具把 CSS 排版属性映射为可在sx中直接书写的系统 Prop(typography、fontFamily、fontSize、fontWeight、textAlign、textTransform、fontStyle、letterSpacing、lineHeight),并自动与theme.typography主题对象联动。读完本文,你将掌握在 Material UI 组件中快速实现排版变体、对齐、截断与字重控制的具体写法,并理解其底层解析机制,能在自己的设计中复用这套"主题驱动"的排版方案。
一、Typography 系统工具能解决什么问题
在 Material UI 中,除了直接使用 <Typography> 组件表达语义化标题/正文外,很多时候我们只是需要给某个容器内的文字临时套用一种排版样式:这一行居中、那一段用正文小字、某个标签加粗。如果每次都为此引入独立的样式类或重复编写长串 CSS,既繁琐又难以与主题保持统一。
Typography 系统工具正是为此设计的。它是一组 style function(样式函数),把所有常见的文字排版能力(对齐、换行、字重、字号、字体族、行高、字间距、字母转换)压缩成一行 sx 代码:
<Box sx={{ typography: 'subtitle2' }}>…</Box> // 直接套用 theme.typography.subtitle2
<Box sx={{ textAlign: 'center' }}>…</Box>
<Box sx={{ fontWeight: 'bold' }}>…</Box>
它的核心优势有两个:
- 写起来简洁:无需新增组件或 class,
sx内部会把上述 Prop 编译成真正的 CSS 规则; - 与主题强绑定:
fontWeight: 'light'这类语义值不是硬编码的魔法数字,而是被解析为theme.typography.fontWeightLight对应的主题 token,改主题即可全局联动。
这套能力来源于 @mui/system 包。Material UI(@mui/material)的所有组件都支持 sx,因此下面的写法在 Button、Card、TableCell 等任何组件的 sx 中同样适用,而不只限于 Box。在文档仓库中,本节对应的可运行 Demo 均存放在 docs/data/system/typography 目录下(每个示例都同时提供 .js 与 .tsx 两个版本以及 .tsx.preview 预览文件)。
二、核心机制:style function 如何把 Prop 变成 CSS
在深入各类写法之前,先了解源码层的执行原理,能帮助你理解"为什么某些取值需要从主题中解析、某些取值会直接透传"。
所有排版工具函数都定义在 typography.ts 中。它们由 style() 工厂函数生成,例如:
// packages/mui-system/src/typography/typography.ts(节选)
export const fontFamily = style({ prop: 'fontFamily', themeKey: 'typography' });
export const fontSize = style({ prop: 'fontSize', themeKey: 'typography' });
export const fontWeight = style({ prop: 'fontWeight', themeKey: 'typography' });
export const typographyVariant = style({
prop: 'typography',
cssProperty: false, // 不映射到单一 CSS 属性,而是整体展开
themeKey: 'typography',
});
const typography = compose(
typographyVariant,
fontFamily,
fontSize,
fontStyle,
fontWeight,
letterSpacing,
lineHeight,
textAlign,
textTransform,
);
从源码可以看出几个要点:
fontFamily、fontSize、fontStyle、fontWeight都声明了themeKey: 'typography',而letterSpacing、lineHeight、textAlign、textTransform没有主题键,因此后者取值会直接作为 CSS 值透传。typographyVariant的cssProperty: false意味着它不生成{ [prop]: value }这样的单属性对象,而是把主题里某个排版变体(如theme.typography.body1)整组展开为font-family、font-weight、font-size、line-height、letter-spacing、text-transform等完整样式。- 九个函数最终通过
compose合并成一个聚合 style function,可整体使用。
取值解析逻辑位于 style.ts 中:字符串取值会被当作主题对象里的点路径(dot path)去查询(例如 'h6.fontSize' 会被 pathInput.split('.') 拆成 ['h6', 'fontSize'] 逐级访问);若主题中找不到对应键,则回退使用你传入的原始值。因此当你传入的主题键存在时走主题、不存在时按原始 CSS 值透传。同时,每次取值都会经过 handleBreakpoints(见 style.ts),这正是 sx 中排版 Prop 也能写 { xs: ..., md: ... } 响应式对象的原因。
三、Variant:一键套用主题排版层级
MUI 默认主题在 theme.typography 下内置了完整的排版层级。你可以直接把某个变体名作为 typography 的值,一次性获得该层级定义的整套字体属性:
<Box sx={{ typography: 'subtitle2' }}>subtitle2</Box> // 套用 theme.typography.subtitle2
<Box sx={{ typography: 'body1' }}>body1</Box> // 套用 theme.typography.body1
<Box sx={{ typography: 'body2' }}>body2</Box> // 套用 theme.typography.body2
更完整的变体示例见 Variant.js。
可用变体名包括默认主题中的 h1–h6、subtitle1、subtitle2、body1、body2、button、caption、overline 等。由于 typography Prop 采用点路径 + 主题查询的机制,前提是该键确实存在于 theme.typography 中;当你为组件定制了额外的变体键(或在主题中删改了层级),这里会随之生效。若写入一个主题中不存在的字符串,则会原样透传并产生无效 CSS,因此建议始终以主题变体键为准。
typography 变体与 Material UI 的 <Typography variant="..."> 使用的是同一份主题数据。区别在于:<Typography> 是一个承载语义(如 component="h1")与自动映射的独立组件;而这里的 typography Prop 只是纯样式快捷方式,适合套用在任意容器文字上,语义结构由你自己控制。
四、Text alignment:文本对齐
控制文本对齐只需使用 textAlign Prop,取值与 CSS text-align 完全一致:left、center、right、justify、start、end 等。
<Box sx={{ textAlign: 'left' }}>…</Box>
<Box sx={{ textAlign: 'center' }}>…</Box>
<Box sx={{ textAlign: 'right' }}>…</Box>
参考 TextAlignment.js 中可以看到一个完整的 justify 段落示例(两端对齐)与左/中/右三种对齐组合的演示。由于 textAlign 在 typography.ts 中没有声明 themeKey,所有取值都直接透传为 CSS,不受主题影响。
五、Text transformation:大小写转换
textTransform 让你在不改动源文本内容的前提下改变大小写呈现:
<Box sx={{ textTransform: 'capitalize' }}>…</Box> // 每个单词首字母大写
<Box sx={{ textTransform: 'lowercase' }}>…</Box> // 全部小写
<Box sx={{ textTransform: 'uppercase' }}>…</Box> // 全部大写
完整示例见 TextTransform.js。这在实际项目中非常适合用来统一"按钮文字全大写"这类设计规范,而无需逐处修改文案。它同样不带主题键,值会原样写入 CSS text-transform。
六、Font weight:字重与主题字重 token
字重有两种写法:语义 token(映射到 theme.typography)与直接数值。
<Box sx={{ fontWeight: 'light' }}>…</Box> // 解析为 theme.typography.fontWeightLight
<Box sx={{ fontWeight: 'regular' }}>…</Box> // 解析为 theme.typography.fontWeightRegular
<Box sx={{ fontWeight: 'medium' }}>…</Box> // 解析为 theme.typography.fontWeightMedium
<Box sx={{ fontWeight: 500 }}>…</Box> // 数值 500 直接透传
<Box sx={{ fontWeight: 'bold' }}>…</Box> // 解析为 theme.typography.fontWeightBold
对应 Demo 见 FontWeight.js。
关于映射细节:fontWeight 的 themeKey 是 typography,当你传入字符串 'light' 时,解析器先在 theme.typography.light 中查找;默认主题并不存在这一键,此时会触发 style.ts 中的 alternate prop 回退逻辑——把查找键改写为 fontWeight + 首字母大写的词尾,最终命中 theme.typography.fontWeightLight。这就是上面注释 // theme.typography.fontWeightLight 的来源。而纯数字 500 不会走字符串路径查询,会直接作为 CSS font-weight: 500 输出,因此你完全可以在两者之间混用。
七、Font size:字号、默认字号与点路径
fontSize 支持三种用法:'default'(取主题默认字号)、主题点路径(如标题层级的字号)、直接数值。
<Box sx={{ fontSize: 'default' }}>…</Box> // 解析为 theme.typography.fontSize
<Box sx={{ fontSize: 'h6.fontSize' }}>…</Box> // 点路径访问 theme.typography.h6.fontSize
<Box sx={{ fontSize: 16 }}>…</Box> // 数值 16,直接以 px 生效
对应示例见 FontSize.js。
其中 'default' 同样依赖 alternate prop 回退:先尝试 theme.typography.default(默认不存在),随后回退为 theme.typography.fontSize。'h6.fontSize' 则是点路径能力的直接体现——即便主题中 h6 本身是一个包含多条字体属性的对象,你也可以只取其中 fontSize 字段(参考 getPath 对 . 分隔路径的解析,见 style.ts)。这一点让系统 Prop 在复用主题局部值时非常灵活,例如对齐某块文字的标题字号但保留其自身字重。数值型的 16 因为没有匹配主题键会原样进入 CSS,浏览器按 16px 解释。
八、Font style:字型风格
fontStyle 用来切换常规/斜体等字形,取值与 CSS 对齐:
<Box sx={{ fontStyle: 'normal' }}>…</Box>
<Box sx={{ fontStyle: 'italic' }}>…</Box>
<Box sx={{ fontStyle: 'oblique' }}>…</Box>
示例见 FontStyle.js。需要说明的是:虽然 API 表中 fontStyle 的 theme key 为 typography,但在默认主题下不存在 theme.typography.italic 之类的键,因此这些字符串最终会走"查找失败 → 原值透传"路径,作为标准 CSS font-style 值输出;若你在主题中自定义了相关键,也可让它走主题解析。
九、Font family:字体族与主题字体
fontFamily 同时支持主题引用与直接书写字体栈:
<Box sx={{ fontFamily: 'default' }}>…</Box> // 解析为 theme.typography.fontFamily
<Box sx={{ fontFamily: 'Monospace' }}>…</Box> // 作为 CSS 字体值透传(通用字体族)
Demo 见 FontFamily.js。
'default' 的解析路径与字重 token 相同:theme.typography.default 不存在时回退命中 theme.typography.fontFamily,也就是 MUI 默认的主题字体栈(中文场景下常配合自定义主题覆盖为系统字体栈)。任何其他值都会被作为字体名/字体栈原样输出,因此你也可以传入 '"Roboto", "Helvetica", "Arial", sans-serif' 这类完整栈。顺带一提,style.ts 中的注释表明这套 alternate prop 机制在项目内部还支持类似 fontFamilyCode 的兄弟键,方便在同一套 API 下切换不同的字体子集。
十、Letter spacing 与 Line height:字间距与行高
这两者不依赖主题,取值直接映射 CSS:
<Box sx={{ letterSpacing: 6 }}>…</Box> // letter-spacing: 6px
<Box sx={{ letterSpacing: 10 }}>…</Box>
<Box sx={{ lineHeight: 'normal' }}>…</Box> // line-height: normal
<Box sx={{ lineHeight: 10 }}>…</Box> // 数值会被作为无单位行高系数
对应 Demo 分别为 LetterSpacing.js 与 LineHeight.js。
两点使用提示:
letterSpacing传入数字会按px处理;若需要按em缩放,可传入'0.1em'形式的字符串,字符串不会经过数值换算;lineHeight的数值是无单位行高(相对自身字体大小缩放),这是排版中最推荐的行高写法,因为字号变化时行高会自动按比例伸缩;'normal'则由浏览器根据字体决定。
十一、完整 API 对照表
下节对应原文档的 API 表格。其中 typography、fontFamily、fontSize、fontStyle、fontWeight 均以 theme.typography 为取值来源,其余项取值直接透传为 CSS。完整导入方式:
import { typography } from '@mui/system';
| Import name | Prop | CSS property | Theme key |
|---|---|---|---|
typography |
typography |
font-family, font-weight, font-size, line-height, letter-spacing, text-transform |
typography |
fontFamily |
fontFamily |
font-family |
typography |
fontSize |
fontSize |
font-size |
typography |
fontStyle |
fontStyle |
font-style |
typography |
fontWeight |
fontWeight |
font-weight |
typography |
letterSpacing |
letterSpacing |
letter-spacing |
none |
lineHeight |
lineHeight |
line-height |
none |
textAlign |
textAlign |
text-align |
none |
textTransform |
textTransform |
text-transform |
none |
值得注意 API 与源码的对应关系(见 typography.ts):表中除 typography 之外的八个单项在源码中都有同名、同 Prop 的具名导出(如 fontFamily、fontSize、fontWeight),它们既能作为聚合函数 typography 的一部分被 sx 使用,也能按需单独 import。同时该模块还导出了 TypographyProps 类型,供你在扩展组件 props 类型时复用这些 Prop 的联合定义。由于每个导出本质上都是 (props) => styleObject 的样式函数,从源码结构看,你还可以把聚合结果传给 styled(),快速打造一个自带整套排版能力的自定义组件(类似 Box 的做法)。
十二、响应式与组合实战
因为每个取值都经过 handleBreakpoints(见 style.ts),所有排版 Prop 都能像 sx 的其他属性一样传入断点对象,实现"小屏居中、大屏左对齐"这类典型排版需求:
<Box
sx={{
textAlign: { xs: 'center', md: 'left' }, // 移动端居中,桌面端左对齐
typography: { xs: 'body2', sm: 'body1' }, // 断点间切换排版层级
}}
>
响应式排版内容
</Box>
你也可以把多个排版 Prop 与间距、颜色等其他系统功能组合在同一个 sx 里,快速完成一条"完整排版":
import Box from '@mui/material/Box';
<Box
component="p"
sx={{
typography: 'subtitle2',
fontWeight: 'medium',
letterSpacing: 1,
textAlign: 'justify',
textTransform: 'uppercase',
m: 1,
}}
>
组合使用多个排版工具
</Box>
需要强调:上述所有写法都建立在 theme.typography 与组件 sx 之上,因此换肤与可访问性收益是全局的——不同主题只要调整 typography 对象,所有用语义 token 书写的文字样式就会同步更新,无需改动业务组件。
十三、小结
Typography 系统工具把文字排版收敛为一套"主题优先、语义化取值、一行 sx 搞定"的 API:
- 层级复用:
typography: 'body1'等值直接继承theme.typography的完整层级; - 主题联动:字重、字号、字体族的语义字符串(
light/default/h6.fontSize…)通过点路径与 alternate prop 机制解析到主题 token; - 直接透传:对齐、大小写、行高、字间距等与主题无关的能力,取原值映射 CSS;
- 响应式免费:全部支持
{ xs, sm, md, ... }断点对象写法。
在 Material UI 项目中,这套工具是介于"手写内联样式"与"完整 <Typography> 语义组件"之间的理想中间层。建议在使用时优先选择语义化取值以维持主题一致性,并在真正需要语义标签与自动字号映射的场合,再让 <Typography variant> 出场。若想进一步探索主题排版对象的结构与所有默认值,可查看上文引用的 typography.ts 及各目录下的可运行 Demo,并在你自己的主题中覆盖 typography 键进行验证。
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 StartedRust0623
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