text-indent 是唯一语义正确、原生支持首行缩进的 CSS 属性,但其生效需满足块级上下文、未被布局模型压制、单位适配中文排版等条件;常见失效原因包括 display 非 block、首行为替换元素、white-space 限制、样式覆盖等;flex/grid 子项中建议用 padding-left 替代或嵌套 div 恢复块流;推荐使用 2em 单位以保障可访问性与响应式;需注意 line-height 协调避免视觉重叠。

text-indent 是唯一语义正确、原生支持首行缩进的 CSS 属性,但它不是“加了就出效果”的开关——能否生效,取决于元素是否处于块级上下文、有没有被布局模型压制、单位是否适配中文排版习惯。
为什么 text-indent: 2em 加了却没反应
常见现象:写了样式,开发者工具里也看到 text-indent: 2em 被声明了,但页面上第一行纹丝不动。这不是代码写错,而是渲染条件不满足:
-
<p>的display计算值不是block(比如被父容器设为flex子项后退化为inline-flex) - 段落开头是
<img>或<svg>,浏览器把该内联替换元素当作“首行起点”,缩进发生在它左边,视觉上等于没动 - 父容器用了
white-space: nowrap或pre,整段被压成单行,“首行”概念失效 - 某处高权重样式覆盖了它,比如重置 CSS 里写了
p { text-indent: 0 },或富文本编辑器输出了style="text-indent: 0"
最快验证方式:打开开发者工具 → 找到目标 <p> → 切到 Computed 标签页 → 查看 display 是否为 block,再点开 text-indent 看最终计算值是不是你设的 2em。
text-indent 在 flex/grid 容器里静默失效怎么办
当 <p> 是 display: flex 或 display: grid 的直接子元素时,它的块级盒行为被格式化上下文压制,text-indent 常常不触发——这不是 bug,是 CSS 布局模型的正常表现。
立即学习“前端免费学习笔记(深入)”;
- 别硬加
display: block试图“修复”,它可能被align-self或justify-content拉偏,且不一定稳定 - 首选替代方案:
padding-left: 2em。它不依赖“首行”语义,对 flex item / grid item 同样生效,视觉结果几乎一致 - 若必须保留
text-indent语义(如兼容旧打印样式),建议把<p>包一层<div>,让外层<div>做 flex/grid 子项,内层<p>回归普通块流 - 别在导航菜单、卡片标题这类本就不该有“段落缩进”语义的地方硬套
text-indent——那是间距问题,该用margin-left或padding-left
单位选 em 还是 ch 还是 px?
中文排版要的是“两个汉字宽度”,但不同单位行为差异很大,直接影响响应式和可访问性:
-
text-indent: 2em:最推荐。1em = 当前元素font-size,缩进随字号缩放,适配系统字体放大和双指缩放;注意 em 是字体大小,不是字符宽度,等宽字体下可能略宽 -
text-indent: 2ch:更贴近语义(1ch ≈ 数字0的宽度),多数中文字体下单字接近 1ch,但 IE 不支持,Safari 对 ch 的实现也不够稳定 -
text-indent: 32px:仅适合字体大小绝对固定、无无障碍需求的场景;用户开启系统字体放大后,缩进会严重失准 -
text-indent: 2%:按父容器宽度计算,和字体完全无关——父容器宽 1000px 时缩进 20px,而字体才 14px,极易失控
移动端尤其要注意:iOS Safari 和部分安卓 WebView 在双指放大页面时,会把 em 当作绝对尺寸重算,导致缩进跳变。可加最小字号限制:html { font-size: max(16px, 4vw); } 防止基准坍塌。
text-indent 和 padding-left 别混用
两者视觉效果看似相似,但语义和行为完全不同:
-
text-indent: 2em只移动第一行文字起始位置,后续行仍对齐左边界,符合中文段落规范;复制粘贴时不会带出空白字符;屏幕阅读器能正确跳过 -
padding-left: 2em是给整个元素加左内边距,整段文字整体右移;即使只有一行,也会占满该宽度;若配合text-align: justify,会导致两端对齐逻辑错乱 - 误用
padding-left还会让响应式断点下缩进失效(它是固定偏移,不随字号缩放);小屏时容易撑破容器 - 表格单元格(
<td>)里text-indent有效,但需确保单元格是display: table-cell(默认就是);行内元素如<span>必须先设display: inline-block或block才能生效
真正麻烦的不是怎么写那行代码,而是缩进之后的 line-height 是否协调——text-indent 只动起点,不改行高计算。如果 line-height 设得太小(比如 1.2),首行末尾和第二行开头容易视觉重叠,得手动调到 1.5~1.6 才稳。



















