图标字体是前端项目中非常常见的方案,像Font Awesome、iconfont、Material Icons等图标库都被广泛使用。但不少人在实际项目中遇到过这样的现象:页面打开时,本来应该显示图标的位置先是一块空白,或者显示成一个方框加内部乱码的字符,等了几百毫秒甚至更久之后,图标突然"闪"一下正常显示出来。这种现象不仅影响观感,还会造成布局偏移,影响页面的加载体验评分。产生这个问题的核心原因是自定义字体文件的网络加载与页面的文本渲染之间没有做好协调,而CSS提供的font-display属性正是用来控制这个协调过程的。

图标闪动的根本原因是什么
要理解闪动问题,需要先弄清楚浏览器是如何渲染网页字体的。当CSS中声明了一个@font-face规则,浏览器并不会立即使用这个字体渲染文字,而是要先下载对应的字体文件。在字体文件下载完成之前,浏览器对使用该字体的文本有两种处理策略:一种是完全不渲染这些文字,先显示空白;另一种是先用一个备选字体(通常是系统字体)渲染,等字体下载完成后再替换。
按照规范,浏览器默认采用的是第一种策略的变体,也就是所谓的阻塞期(block period)。在这段时间内,文字是不可见的,但如果阻塞时间超过约3秒,浏览器会放弃等待,用备选字体渲染。对于图标字体来说,这个问题尤其明显,因为图标本质上是一个普通字符,只是字体文件把它绘制成了图形。在字体没加载完成时,备选字体不认识这个字符,就会渲染成方框或乱码,等真正的图标字体下载完成后,字符突然变成图标,视觉上就产生了"闪动"。
另外要注意,如果字体文件较大、网络较慢,或者字体文件放在了渲染关键的请求链上,闪动会被进一步放大。所以在解决问题之前,建议先用浏览器开发者工具的Network面板查看字体文件的实际加载时间,判断问题主要出在下载慢还是渲染策略上。下载慢可以通过压缩字体、按需子集化、使用woff2格式等手段优化,而渲染策略就要靠font-display属性来控制了。
font-display属性的四个取值详解
font-display属性只能写在@font-face规则内部,用来告诉浏览器在字体加载期间如何处理使用该字体的文本。它有五个取值,其中auto表示交给浏览器决定(通常等同于block),另外四个是明确的行为模式,理解它们需要先建立两个时间概念:阻塞期和交换期。阻塞期内文字不可见,交换期内用备选字体显示,字体到达后随时替换。
@font-face {
font-family: 'my-icon-font';
src: url('iconfont.woff2') format('woff2'),
url('iconfont.woff') format('woff');
font-weight: normal;
font-style: normal;
/* 核心配置 */
font-display: swap;
}四个取值的行为差异如下表所示:
| 取值 | 阻塞期 | 交换期 | 适用场景 |
|---|
| block | 较短(约3秒),文字不可见 | 无限期,字体到达后替换 | 必须使用自定义字体的文本 |
| swap | 极短(约100毫秒),几乎立即显示 | 无限期,字体到达后替换 | 强调内容优先可见的普通文本 |
| fallback | 极短(约100毫秒) | 较短(约3秒),超时后不再替换 | 兼顾速度与视觉体验的折中方案 |
| optional | 极短(约100毫秒) | 几乎为0,由浏览器决定是否交换 | 纯装饰性字体,完全避免布局偏移 |
具体来说,block是默认行为的显式写法,图标位置会先空白一阵子再显示图标,适合图标 absolutely 不能显示成乱码的场景;swap会立刻用备选字体渲染,字体下载完成后立即替换,文字内容马上可见,但对图标字体来说,备选字体会把图标字符显示成方框,闪动依然存在,只是从空白变成了乱码再变图标;fallback比较有趣,它给字体约3秒的下载窗口,如果3秒内下载完成就替换,否则永远使用备选字体,下次访问时浏览器已有缓存才会真正用上自定义字体;optional则几乎完全放弃首次加载的字体替换,交给浏览器根据网络状况判断,最能保证布局稳定。
图标库场景下的推荐配置与link预加载
针对图标字体,我推荐的做法是使用font-display: block配合字体预加载。原因是图标字体的字符在备选字体中无法正常显示,swap和fallback都会导致乱码方框出现,视觉体验反而更差。block虽然有一小段空白,但只要通过预加载把字体文件提前到关键请求链的前面,空白时间就可以压缩到几乎不可感知的程度。
预加载需要使用<link>标签的rel="preload",并正确声明as="font"和crossorigin属性。这里有个非常容易踩的坑:crossorigin必须写,即使字体和页面同源。因为字体文件在浏览器内部始终是以匿名跨域方式请求的,如果preload时没有带crossorigin,浏览器会发起两次请求,预加载的缓存根本不会被字体加载复用,等于白做。写法如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!-- 关键:提前加载字体文件,crossorigin必须保留 -->
<link rel="preload" href="/fonts/iconfont.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/iconfont.css">
</head>
<body>
<i class="icon icon-user"></i>
</body>
</html>
同时,在字体CSS文件中声明font-display。如果你使用的是第三方图标库的托管CSS(比如通过CDN的link标签直接引入),无法直接修改对方的@font-face,有两个办法:一是把字体CSS下载到本地自己维护,在@font-face里加上font-display: block;二是使用CSS的覆盖技巧,在自己样式表中重新声明一个同名的@font-face,指向同一个字体文件并补上font-display,浏览器会以后声明的规则为准。
除了配置层面,工程上还可以做几件事来根治闪动:优先使用woff2格式,体积比woff小百分之三十左右;如果只用到图标库中的一小部分图标,使用iconfont平台的子集化功能生成精简字体;给图标容器设置固定的宽高,即使字体未加载完成也不会引起布局偏移;条件允许的话,考虑把关键图标改用内联SVG实现,SVG随HTML一起到达,完全不存在字体加载延迟的问题,这也是目前社区越来越推荐的方向。
最后总结一下:font-display控制的是字体加载期间的文本渲染策略,图标字体推荐block加preload预加载的组合,普通正文可以用swap或optional,再配合字体子集化和固定尺寸容器,就能把图标闪动问题降到用户几乎无感知的程度。
font-display图标库加载闪动web fonts修改时间:2026-09-14 03:32:41
免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260914/56428.html,基于非商业用途的前提下,欢迎转载或二创本作品。