::first-letter 对中文段落默认失效,因浏览器仅识别 ASCII 字符为首字符;需用零宽空格诱导匹配,并配齐 float: left、line-height: 0.75、font-size 三属性才能实现真正下沉。

直接写 ::first-letter 对中文段落大概率静默失效,不是 CSS 写错了,而是浏览器根本没触发伪元素——它默认只认 ASCII 字母、数字或标点为首字符,纯汉字开头不匹配。
为什么写了 ::first-letter 却完全没反应
这不是样式被覆盖,而是选择器压根没命中。常见失效场景包括:
-
<p>\n 今天</p>:首字符前有换行或空格,被忽略 -
<p><strong>今</strong>天</p>:首字被<strong>包裹,不在文本流顶层 -
<div style="display: flex"><p>今天</p></div>:父容器是flex或grid,切断文本流 -
<p>《今天</p>:全角标点《被当作“首字符”,放大后溢出严重
::first-letter 真正下沉必须配齐的三个属性
只设 font-size 是假下沉,只会撑高整行;要文字环绕、视觉沉入,三者缺一不可:
-
float: left:唯一能触发文字绕排的属性,不加就只是变大 -
line-height: 0.75(无单位):必须显式设置,继承父级line-height: 1.6会让放大后的首字像砖块一样顶开第二行 -
font-size: clamp(2rem, 4vw, 3.5rem):中文建议响应式写法;固定值至少2.5em,2em在多数字体下无下沉感
中文段落生效的实操补救方案
当内容无法控制为英文开头,又不能改 DOM 结构时,可用零宽空格 (U+200B)诱导识别:
立即学习“前端免费学习笔记(深入)”;
<p>​今天天气很好</p>
配合 CSS:
p::first-letter {
float: left;
font-size: 3em;
line-height: 0.75;
margin-right: 0.2em;
}
/* 必须重置 ::before,否则零宽空格可能影响行高 */
p::before {
content: "";
display: inline;
}
注意: 不能替换成普通空格或 ;若内容来自 CMS 或用户输入,需在服务端或 JS 渲染阶段自动注入。
容易被忽略的底层细节
真正卡住上线的从来不是语法,而是这些渲染层事实:
- 中文字体无 ascender/descender 基线,同一套
line-height: 0.75在思源宋体下刚好,在 Noto Sans CJK 下可能截顶——必须用最终上线字体实测 - 移动端 viewport 缩放后,iOS Safari 偶有重绘异常;可加
@media (max-width: 768px) { p::first-letter { float: none; display: inline-block; vertical-align: top; } } -
overflow: hidden必须加在父<p>上清除浮动,否则高度塌陷导致后续段落上移重叠;别用clear: both,它需要额外 DOM 节点


















