text-indent仅对块级框且处于标准BFC的元素生效;失效主因是display非block、浮动/弹性布局干扰、内联替换元素遮挡或高权重样式覆盖;推荐用2em单位,避免与padding-left混用。

text-indent 是唯一语义正确、原生支持首行缩进的 CSS 属性,但它极易“写了却没效果”——问题几乎从不在于属性本身,而在于渲染上下文是否满足条件。
为什么 text-indent 加了却没缩进
这不是代码写错,而是浏览器拒绝执行:它只对生成块级框(block-level box)的元素生效,且要求该元素处于标准块格式化上下文(BFC)中。常见失效场景包括:
-
<p>被父容器设为display: flex或display: grid—— 此时<p>变成 flex item / grid item,不再是块级框 -
<p>自身被设为display: inline、inline-block或float: left - 段落开头是
<img>或<svg>等内联替换元素,缩进仍发生,但视觉上被遮挡或错位 - 某处高权重样式覆盖了它,比如富文本编辑器输出的
p { text-indent: 0 !important } - 用了
white-space: nowrap或white-space: pre,导致“首行”概念失效
最快验证方式:打开开发者工具 → 查看目标元素的 Computed 面板 → 确认 display 值为 block(或 table-cell),且 text-indent 的最终计算值不是 0。
text-indent 该用 em 还是 px?
中文排版习惯的“两字缩进”,推荐固定用 2em,而非像素值。原因很实际:
立即学习“前端免费学习笔记(深入)”;
-
2em相对于当前元素的font-size,字体放大、系统开启“更大文本”辅助功能时,缩进同步变宽,观感稳定 -
32px在 16px 字体下看似刚好,但用户缩放 150% 后,文字变大而缩进僵硬不变,首行反而显得太窄 -
2rem依赖根元素字号,若项目用 JS 动态改html { font-size }(如夜间模式切换),缩进会意外跳变 -
2ch语义更准(1ch ≈ 字符 “0” 宽度),但旧版 Safari 和部分中文字体下表现不稳定,生产环境慎用
注意:2em 不等于“两个汉字像素宽度”,它约等于当前字号的两倍——在多数中文字体中,这恰好接近视觉上的两字符,已是目前最平衡的选择。
text-indent 和 padding-left 别混用
两者效果本质不同,混用会导致视觉混乱:
-
text-indent: 2em:只推第一行开头,第二行及之后仍紧贴左边界,符合中文段落规范 -
padding-left: 2em:整个内容区域右移,所有行(包括单行段落)都整体偏移,形成“左边一块空白” - 若同时设置,会出现“第一行缩进 + 整体右移”,结果比预期多出一倍偏移,尤其在响应式断点下更难调试
- 表格单元格(
<td>)里想缩进首行,应优先用text-indent;若需整列文字右移,则用padding-left,不要交叉使用
真正麻烦的是富文本场景:编辑器导出的 HTML 可能同时含内联 style="text-indent: 2em" 和全局 .content p { padding-left: 1em },此时缩进逻辑互相覆盖,必须统一归口到 CSS 类控制。
Flex/Grid 容器里 text-indent 失效怎么办
这不是 bug,是 CSS 格式化上下文变更的自然结果。强行给子元素加 display: block 可能临时修复,但不可靠:
- Flex item 默认
width: auto,即使设了display: block,也可能因宽度未显式定义而退化 - Grid item 的行为更复杂,
text-indent很可能被主轴对齐(justify-items)覆盖 - 更稳妥的做法是换思路:用
padding-left: 2em替代 —— 它不依赖“首行”语义,对任意 display 类型的元素都生效,视觉差异极小 - 若必须保留语义(如打印样式需兼容旧系统),可加一层包裹
<div class="indent"><p>…</p></div>,再对.indent设padding-left,把样式逻辑从语义层剥离
最后提醒一句:缩进不是万能间距工具。导航项、卡片标题、按钮文字这些本就不该有“段落首行缩进”语义的地方,硬套 text-indent 只会让维护成本陡增——那是 margin-left 或 padding-left 的职责。



















