必须设置 font-display: swap 以避免文字闪动或空白,src 按 woff2→woff 优先级排序,中文字体需用 unicode-range 分割并确保 font-weight/style 与文件元数据一致。

直接用 @font-face 引入自定义字体,不加防护措施,大概率会遇到文字闪动、空白、回退失败或加载阻塞渲染等问题。关键不在“能不能用”,而在于“怎么让浏览器按你预期的方式加载和显示”。
font-display 是必须设置的控制开关
默认情况下,浏览器对未就绪字体采用 font-display: auto,行为因引擎而异:Chrome 可能 block 3s 后 fallback,Firefox 更激进,Safari 则倾向延长 block 时间。这会导致首屏文字长时间空白或突然重绘。
推荐明确指定为 swap:
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
font-display: swap;
}为什么选 swap:它保证文本立即用系统字体渲染,等自定义字体加载完成后再无感替换,兼顾可读性与最终效果。其他值如 optional(适合非关键字体)、fallback(适合图标字体)也各有所用,但 swap 是中文字体最稳妥的起点。
立即学习“前端免费学习笔记(深入)”;
src 声明要按优先级+格式兼容性排序
浏览器按 src 列表从左到右尝试加载,遇到第一个支持且可解析的格式就停。顺序错了,可能绕过更优格式(比如跳过 .woff2 去加载更重的 .ttf)。
现代项目应按以下顺序写:
-
url('font.woff2') format('woff2')—— 体积最小、压缩最优,所有现代浏览器都支持 -
url('font.woff') format('woff')—— 兜底给老版 Android 或 IE11 - 避免写
.eot或.svg—— IE9 以下已无实际维护价值,加了反而增加解析开销
别把 .ttf 放在前面:它没压缩,体积通常是 .woff2 的 2–3 倍,拖慢首字渲染。
中文字体必须考虑 unicode-range 分割
一个完整中文字体文件(如思源黑体)动辄几 MB。@font-face 默认加载全部字符,但页面可能只用几十个汉字+ASCII。不切分,就是浪费带宽和阻塞渲染。
用 unicode-range 按需加载:
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
unicode-range: U+4E00-9FFF; /* 基本汉字 */
}
@font-face {
font-family: 'MyFont';
src: url('myfont-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}要点:
- 中文范围常用
U+4E00-9FFF(基本汉字)、U+3400-4DBF(扩展A)、U+20000-2A6DF(扩展B,慎用) - 多个
@font-face块共用同一font-family名,浏览器自动合并匹配 - 别指望靠
unicode-range完全解决体积问题——先做子集化(如用pyftsubset工具),再配合该属性
font-weight 和 font-style 必须与实际字体文件一致
很多人复制粘贴示例时照搬 font-weight: normal,但下载的字体文件本身可能是“Bold”变体。浏览器发现声明与文件元数据不匹配,会拒绝应用该字体,或强行降级到系统字体。
验证方式很简单:
- 用字体查看工具(如 FontForge、Transfonter 网站)打开 .woff2 文件,看其内置
weight和style值 - 在
@font-face中严格对应填写,例如:font-weight: 700、font-style: italic - 若一套字体含多个粗细,每个变体都要单独写一个
@font-face块,并配好对应src和属性
漏掉这点,font-weight: bold 在元素上就永远无效——不是 CSS 写错了,是字体文件根本没被识别为 bold 变体。
真正麻烦的从来不是“怎么写 @font-face”,而是字体文件本身的元数据是否干净、子集是否合理、font-display 是否覆盖所有加载路径、以及中文字体是否被当成单个大包硬塞给用户。这些细节不抠,再漂亮的字体也会在真实网络下崩出各种不可见的裂痕。


















