CSS font-size 字体大小与实现小于 12px 字体
font-size 是最常写的 CSS 属性之一,但它有两个坑值得单独记一笔:一是相对单位到底相对谁,em 在嵌套结构里会连乘放大,很容易失控;二是想做出小于 12px 的字,中文环境下浏览器有最小字号限制,直接写 font-size: 10px 在某些浏览器上不生效,得换思路。这篇把取值规则和小字号方案连着可运行示例一起整理。
作用
用于指定字体的大小
除了直接决定文字大小,它还是一堆相对单位的基准:子元素的 em、ex、ch 都以它为参照,line-height: 1.5 这种无单位行高也是乘在它上面。所以改一个容器的 font-size,往往会牵动内部一整片布局。
值
px:绝对大小,不会随着操作系统所认为的屏幕分辨率的大小改变而改变。em/ex:相对于父元素的文字的大小。例如,0.5em就是当前元素的父元素的字体大小的一半。- 百分比:相对于父元素的文字的大小。例如,
50%就是当前元素的父元素的字体大小的一半。
严格说,em 和百分比在 font-size 上参照的是父元素计算后的 font-size。这个「计算后」很关键,因为它会层层累积:外层 1.2em、里层再 1.2em,实际是 1.44 倍,嵌套三四层文字就大得不像话了。所以真要用相对单位,我更推荐 rem——它固定参照根元素 <html> 的字号,不管嵌套多深都是同一个基准,不会连乘。
ex 用得少,它参照的是当前字体小写字母 x 的高度,会随字体变化。想按字符宽度算的话还有 ch,参照数字 0 的宽度,做等宽对齐时偶尔有用。
除此之外还有一组关键字:smaller、larger 相对父元素放大缩小一档,medium、small、large 这类绝对关键字对应浏览器预设的一套字号表。实际项目里基本不用,因为具体像素值由浏览器决定,不好控制。
tip
一般情况下浏览器默认字体大小为 16px
这个 16px 是浏览器的默认值,用户可以在设置里改。做无障碍友好的站点时,正文字号最好用 rem 跟着这个基准走,用户放大字号后页面才能一起变大。有些项目为了「1rem = 10px」方便换算,会给 html 设 font-size: 62.5%,这个写法保留了用户设置的比例关系,比直接写 font-size: 10px 要好。
示例
下面这段把几种取值放在一起对照。重点看第一组:外层 div 是 20px,内部 p 写 0.5em,算出来是 10px,参照的是父元素的 20px 而不是根元素。而后面那几个直接挂在 body 下的 p,1em、2em、100%、200% 参照的都是 body 继承来的默认 16px,所以分别是 16px、32px、16px、32px。
可以看出 1em 和 100%、2em 和 200% 效果完全一致——在 font-size 这个属性上,两者的参照物和算法就是同一套。
::: demo [vanilla]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div style="font-size: 20px">
这是 div 的文字 font-size: 20px
<p style="font-size: 0.5em">这是 p 标签的文字 font-size: 0.5em</p>
</div>
<p style="font-size: 1em">这是 p 标签的文字 font-size: 1em</p>
<p style="font-size: 2em">这是 p 标签的文字 font-size: 2em</p>
<p style="font-size: 0.75ex">这是 p 标签的文字 font-size: 0.75ex</p>
<p style="font-size: 100%">这是 p 标签的文字 font-size: 100%</p>
<p style="font-size: 200%">这是 p 标签的文字 font-size: 200%</p>
<p style="font-size: 75%">这是 p 标签的文字 font-size: 75%</p>
</body>
</html>
{
"show": true
}
:::
实现小于 12px 字体的方法
设计稿上给了 10px 的辅助文字,我们照着写 font-size: 10px,在 Chrome 中文环境下却发现渲染出来还是 12px。原因是浏览器有一个「最小字号」设置,中文环境下默认是 12px,比它小的值会被强行抬回 12px。这是浏览器为了中文可读性做的保护,不是我们的 CSS 写错了。
早年间流传的解法是加 -webkit-text-size-adjust: none 来关掉这个限制。这个方案在现在的桌面版 Chrome 上已经失效了,属于早期版本的行为,别再照抄。这个属性如今主要的用途是在移动端阻止横竖屏切换时的文字自动放大,和突破最小字号无关。
真正可靠的做法是「先给合法字号,再整体缩小」:把 font-size 写成不小于 12px 的值,然后用 transform: scale() 把元素视觉上缩下去。缩放是渲染层面的几何变换,不受最小字号约束,想要 10px 就在 12px 的基础上 scale(0.8333)。
下面的示例里三个 span 都是 font-size: 12px,靠不同的缩放比例做出 12px、10px、6px 三档:
::: demo [vanilla]
<html>
<div>
<span style="font-size: 12px;display: block;">测试</span>
<span style="font-size: 12px;display: block;transform: scale(0.8)">
测试 10px
</span>
<span style="font-size: 12px;display: block;transform: scale(0.5)">
测试 6px
</span>
</div>
</html>
:::
注意示例里每个 span 都加了 display: block。这不是可选项——transform 对普通行内元素不生效,必须先让元素变成 block 或 inline-block 才能缩放。
用这个方案有两个后果要提前想到。一是元素占位不变:scale 只改变视觉呈现,布局盒子仍然按缩放前的尺寸参与排版,所以文字周围会多出一圈空白。想让占位也跟着收缩,得配合负 margin 手动补偿,或者给父元素设一个明确的宽高。
二是缩放原点默认在元素中心,文字会向中间收,左右两侧都留白。如果这段文字需要和上方内容左对齐,加一句 transform-origin: left center 把原点挪到左边,缩放后左边缘就不动了:
.tiny-text {
font-size: 12px;
display: inline-block;
transform: scale(0.8333);
transform-origin: left center;
}
最后一点:缩放后的文字是把 12px 的字形栅格化结果再压小,笔画细节会有损失,中文小字尤其容易糊。所以这套方案适合放页脚版权、角标数字这类辅助信息,正文别这么干。

还没有留言,来发表第一条吧~