动态注入含@font-face的样式表引发文本短暂不可见问题
解决动态注入含@font-face的外部样式表导致文本短暂不可见的问题
兄弟,你碰到的这个是典型的 FOIT(Flash Of Invisible Text) 问题,再加上动态加载外部样式表的特殊性,才会出现没法直接操作样式表规则的情况。我给你拆解几个实用的解决方案:
一、最省心的方案:给@font-face加上font-display: swap
FOIT的根源是浏览器默认会等自定义字体加载完才显示文本,而font-display: swap能告诉浏览器:先显示系统 fallback 字体,等自定义字体加载完成后再无缝替换,从根源上解决文本短暂不可见的问题。
如果你能控制外部样式表的内容,直接在每个@font-face规则里加这个属性就行:
@font-face { font-family: 'YourCustomFont'; src: url('your-font.woff2') format('woff2'); font-display: swap; /* 关键属性,解决FOIT */ }
要是没法修改外部样式表,接着往下看其他方法。
二、正确监听样式表加载,确保能访问它的规则
你说样式表没出现在document.styleSheets里,大概率是两个原因:要么是样式表还没加载完成,要么是跨域导致浏览器限制访问。
1. 等待样式表加载完成再操作
动态注入样式表时,一定要等它加载完成后再去遍历document.styleSheets。用link元素的onload事件来处理:
const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = '你的外部样式表URL'; // 样式表加载完成后再处理规则 link.onload = function() { [...document.styleSheets].forEach(sheet => { try { // 匹配到刚加载的样式表 if (sheet.href === link.href) { // 遍历所有规则,找到@font-face并修改 [...sheet.cssRules].forEach(rule => { if (rule.type === CSSRule.FONT_FACE_RULE) { rule.style.fontDisplay = 'swap'; } }); } } catch (e) { console.log('这个样式表是跨域的,暂时没法访问cssRules'); } }); }; document.head.appendChild(link);
2. 处理跨域样式表的访问限制
如果外部样式表是跨域的,浏览器会因为同源策略阻止你访问它的cssRules,这时候需要两步操作:
- 让样式表所在服务器的响应头加上
Access-Control-Allow-Origin,允许你的域名访问; - 同时在动态创建的
link元素上添加crossorigin属性:
link.crossOrigin = 'anonymous'; // 如果需要携带凭证,就用'use-credentials'
这样处理后,就能正常访问跨域样式表的规则了。
三、绕过样式表访问:预加载字体+自定义@font-face规则
要是上面的方法都没法实现(比如没法改服务器配置,也没法修改外部样式表),可以换个思路:
- 先预加载字体文件,确保字体加载完成后再应用样式;
- 自己在页面中添加带有
font-display: swap的@font-face规则,提前定义字体行为。
示例代码:
// 1. 预加载字体文件 const fontPreload = document.createElement('link'); fontPreload.rel = 'preload'; fontPreload.href = '你的字体文件URL'; fontPreload.as = 'font'; fontPreload.type = 'font/woff2'; fontPreload.crossOrigin = 'anonymous'; // 跨域字体一定要加这个 // 2. 字体预加载完成后,添加自定义@font-face规则 fontPreload.onload = function() { const style = document.createElement('style'); style.textContent = ` @font-face { font-family: 'YourCustomFont'; src: url('你的字体文件URL') format('woff2'); font-display: swap; } `; document.head.appendChild(style); // 最后注入外部样式表 const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = '你的外部样式表URL'; document.head.appendChild(link); }; document.head.appendChild(fontPreload);
这样本地的@font-face规则会先生效,加上font-display: swap就不会出现文本不可见的情况了。
内容的提问来源于stack exchange,提问作者adam7918
相关产品推荐
相关产品推荐

