当动态加载新的 CSS 文件时,字体出现闪烁问题

16

我正在使用Google Webfont Loader来加载我的网页字体,并使用回调函数,效果很好。

但是,当加载一些组件时:Google +1按钮、Twitter搜索小部件和Add This按钮,它们会向DOM添加新的样式表,并使浏览器再次渲染网站。这会导致字体在每个新添加到DOM中的样式表中消失然后重新出现。

我可以隐藏字体,直到组件被加载完成,但它们往往加载得比较慢,这会给用户留下不良的体验,大约需要1秒钟的无标题网站。

有什么办法可以强制字体不重新绘制,或者如何阻止从Google、Twitter 和FB的嵌入脚本中动态加载CSS?

更新:演示地址在这里:http://kristoferforsell.com/dev/fontexample/


1
你有示例吗?你能缩小共享组件中哪个是导致闪烁的原因,因为根据我的经验,它们不应该对整个页面产生任何影响。 - CherryFlavourPez
当然,这是一个关于闪烁的快速示例。这个会因为常规的 FOST 先闪烁一次,然后当 Add This 的样式表启动时再闪烁一次。第二个闪光/故障适用于每个附加的样式表。如果我添加 Twitter 小部件,就会有另一个闪光或故障。http://kristoferforsell.com/dev/fontexample/ - user192965
我只很少看到AddThis按钮,这似乎指向那里存在问题-您确定加载它们的JS都正确吗? - CherryFlavourPez
我首先使用Google Webfont Loader加载网络字体,在回调函数中加载AddThis,然后它应该神奇地出现。这就是字体闪烁的地方,我在Chrome、FF和Safari中都遇到了这个问题。如果您刷新浏览器窗口几次,就更容易发现了。 - user192965
6个回答

14

目前浏览器和@font-face属性存在的问题是闪烁。当字体加载完并且页面更新以反映该字体时,就会出现闪烁。如果您想完全消除“闪烁”,唯一确定的方法是在样式表中将字体作为数据URI包含其中。当然,使用标准的“安全”字体也可以消除闪烁。

数据URI允许您在样式表中嵌入字体代码,因此刷新页面以显示所需的字体时不会出现闪烁。使用数据URI将明显增加任何样式表的文件大小(kb)。

在线转换为base64代码的工具可以在这里找到。

@font-face的用法如下....

 @font-face {
font-family: "My Font";
src: url("data:font/opentype;base64,[   the base64 code here   ]");
}

7
不确定是否能解决您的问题,但您可以使用css将元素的可见性设置为隐藏,直到字体加载完成。Google的API提供了wf-loadingwf-active类来解决这个问题,它们会被添加到body中。
我通常会为@font-face规则设置单独的样式表,在其中加入以下规则,其中replace是要替换的元素的类,对于您来说,只需是p标记。 .wf-loading .replace { visibility: hidden;} 对于您的情况应该是 .wf-loading p { visibility: hidden;} 然后,一旦web字体加载完成,JS会在body上放置wf-active类,您的文本就会显示出来。请告诉我该方法的效果如何,如果有任何问题,请随时与我联系。另外,也许值得搜索“未经样式处理的内容闪烁”或“未经样式处理的文本闪烁”,因为这是一个众所周知且有记录的错误。

谢谢,但我们遇到的问题是,最初字体加载并正确显示,没有太多FOUC。在字体初始化后,其余的“social”js正在被加载(异步),这些都带有自己的CSS。一旦该CSS被加载,Web字体就会被呈现,这会导致每个CSS文件一个闪烁的速度。我们一直在考虑阻止预先加载社交JS,但那将会使DOM的呈现停滞太久。所以真正的问题是:如何避免在加载新的CSS时重新呈现字体。 - Kasper
也许通过减少CSS文件的数量可以更容易地减少闪烁? - vincicat
我们只使用一个CSS文件,但第三方JavaScript也会加载自己的CSS,这会导致闪烁问题。 - Kasper

7

我可以提供一个简单而有效的技巧来解决这类问题。如果您实现了这个技巧,用户将会看到整个页面一次性加载完毕(包括正确的Web字体),但需要等待一段时间。一旦加载完成,页面不会出现闪烁或变化。 将整个页面内容放在一个div中,并将其可见性设置为隐藏。然后使用js在整个页面(包括样式表等)加载完成后将其可见性打开。 以下是代码:

<head>
<script>
function show()
{document.getElementById('wrapper').style.visibility='visible';}
</script>
</head>
<body onload="show()">
<div id="wrapper">
...your entire page contents...
</div>
</body>
onload 确保只有整个页面都加载完毕后才切换可见性。虽然我没有使用 Web Fonts,但我使用这个技巧来淡入 此网站 的全部内容,而不需要进行任何更改或更新。但是,在整个页面显示之前会有一定的延迟。 编辑:我在链接到的网站中添加了 Google Web Fonts。仍然可以正常工作,没有 font-face 闪烁。

啊,是的,那个方法应该可行,希望它能帮助到很多遇到同样问题的人。但对于我的情况来说,这并不适用,因为这会让我长时间面对空白页面,我的加载顺序如下以限制加载时间:加载网络字体 -> 初始化站点(因为DOM和字体已经准备好)-> 加载第三方脚本,例如Twitter搜索小部件(因为它非常慢),这就是我遇到闪烁的地方。任何其他方式都会让用户面对1-2秒的空白页面,这有点太多了。但还是谢谢! - user192965

0

我完全理解你所说的延迟过程,即在实际展示商品之前等待窗口加载。Abhranil提供了一个很好的解决方案,但你可以进一步采用他的解决方案。你可以使用jQuery的ajax来加载使用特殊字体类型的特定页面内容。为什么?因为ajax带有一个名为beforeSend()的特殊函数。在beforeSend函数()中,你可以加载一个非常酷的礼物动画,它将在你的主要内容准备好被查看之前显示在你的屏幕上。

利用这个时刻向你的观众展示一些创意,让他们期待主要活动的到来!


0

最好且最简单的答案是在指定字体时添加font-display: block

@font-face {
   font-display: block; /* Fix flickering */
}

你还应该在 HTML 文件中预加载字体

<head>
  <link rel="preload" as="font" href="/path_to_your_font.ttf">
  <-- repeat for all typeface -->
</head>

0
这只是一种猜测,因为我还没有测试过: 你能创建另一个仅包含那些社交网络按钮的 HTML 页面,并将其加载到 iframe 中吗?然后,只有当文档完全加载时才设置 iframe 的 src,这样它就不会阻塞任何操作。
在 HTML 中:
<iframe id="socialMedia"></iframe>

在脚本中:

$(document).ready(function() {
   $('#socialMedia').src = "http://mysite.com/mysocialmediastrip.html";
});

其中mysocialmediastrip.html包含所有社交媒体按钮。设置src将导致该iframe重新加载并拉取该内容,但是如果我没记错的话,页面的其余部分将保持不变--所有按钮渲染都将在mysocialmediastrip.html中完成,而不是在您的主页面中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接