頁面字體閃一下?這兩個標準能幫到你

本文做者來自 360 奇舞團的前端開發工程師何文力,同時也是 W3C CSS 工做組的成員javascript

現象

當咱們在瀏覽一些使用自定義字體的網站,或在開發中使用 @font-face 設置自定義字體時,時常會看到一個現象:頁面結構和圖片出來了,但文字區域是空白的。這種現象被稱之爲 FOIT (Flash Of Invisible Text)。css

MSNBC on Firefox

緣由

一般,咱們經過@font-face規則定義讓瀏覽器加載使用第三方字體。這些寫在 CSS 文件中的規則,瀏覽器必須待文件下載結束並解析以後才能開始下載字體文件。而要真正地觸發字體文件下載,還要知足一些條件,根據 Zach Leatherman 的這篇文章,要觸發字體下載,還要知足如下的條件:前端

  • 合法的 @font-face 規則,而且當前瀏覽器須要支持 src 列表中給出的格式
  • 文檔中有節點使用了 @font-face 中相同的 font-family
  • 在 Webkit 和 Blink 引擎中,使用該 font-family 的節點不能爲空
  • 若是 @font-face 中指定了 unicode-range,出現的文字內容還必須落在設定的 Unicode 範圍中

當上述全部條件知足,瀏覽器纔會開始下載字體文件,這也意味着,瀏覽器不單單須要解析 CSS 內容,還要解析頁面內容才能決定是否須要下載字體。當瀏覽器開始下載字體,使用了該 font-family 的全部文本被隱藏,致使頁面出現文本空白的狀況。java

解決

在字體相關的 W3C 標準中,CSS Fonts Module Level 3 中的 font-display 屬性以及 CSS Font Loading API 標準能夠解決相關問題。web

font-display

font-display 屬性添加於 CSS Fonts Module Level 3 中,已有大部分瀏覽器支持該屬性。api

font-display 在 CSS 層面上提供了此類問題的解決方法,它提供了五個屬性:瀏覽器

  • auto:使用瀏覽器默認的行爲;
  • block:瀏覽器首先使用隱形文字替代頁面上的文字,並等待字體加載完成再顯示;
  • swap:若是設定的字體還未可用,瀏覽器將首先使用備用字體顯示,當設定的字體加載完成後替換備用字體;
  • fallback:與 swap 屬性值行爲上大體相同,但瀏覽器會給設定的字體設定加載的時間限制,一旦加載所需的時長大於這個限制,設定的字體將不會替換備用字體進行顯示。 Webkit 和 Firefox 中設定此時間爲 3s;
  • optional:使用此屬性值時,若是設定的字體沒有在限制時間內加載完成,當前頁面將會一直使用備用字體,而且設定字體繼續在後臺進行加載,以便下一次瀏覽時能夠直接使用設定的字體。

CSS Font Loading API

除了 CSS 層面上解決問題,CSS Font Loading API 在 JavaScript 層面上也提供瞭解決方案。經過監聽加載事件,咱們能夠在字體加載完成後經過替換 class 達到 CSS 中 swap 屬性值的效果。字體

瀏覽器支持方面也仍是通常優化

FontFace 接口支持狀況網站

FontFaceSet接口支持狀況

css-font-loading-api-comp-fontfaceset

標準中主要提供了FontFace接口加載字體,而且 document.fonts 對象爲一個 FontFaceSet 接口,他是一組FontFace的集合,管理了頁面上全部字體的狀態。

FontFace 接受三個參數:font-family 名稱、字體資源位置以及字體設定(可選)。

首先,要在 JavaScript 中加載字體,咱們要new一個 FontFace 並將其添加到全局 FontFaceSet 中:

const Aclonica = new FontFace('Aclonica', 'url(./Aclonica.ttf)');
// 添加到全局的 FontFaceSet 中
document.fonts.add(Aclonica);
複製代碼

第二步:調用 FontFaceload 方法開始加載,load方法將返回一個 Promise。當咱們的字體加載完以後,就能夠經過變換 class 的換上新字體。

Aclonica.load().then(() => {
    // 當字體加載完以後,咱們就能夠經過替換 class 的方法替換掉默認的字體
    // 此處的邏輯也能夠是你的字體渲染策略
    document.body.classList.add('use-aclonica');
})
複製代碼
.use-aclonica {
    font-family: Aclonica;
}
複製代碼

不夠完美

咱們經過上述方法進行優化以後,雖然沒有了 FOIT 現象,可是實際效果倒是這樣的:

fout

咱們發現,字體加載完以後頁面仍是不可避免地閃了,這是因爲備用字體和定義的字體外形相差過大致使的視覺效果,這種現象又被稱之爲 FOUT (Flash Of Unstyled Text)。對於正在閱讀文章的用戶來講,顯然不是很好的體驗。

小結

CSS Fonts Module 以及 CSS Font Loading API 這兩組標準都給前端字體不管在渲染上仍是控制上賦予了更多能力,隨着咱們更深刻地研究規範,相信會給字體加載以及渲染方面的問題帶來更多的解決方案。

文內連接

www.zachleat.com/web/compreh…

drafts.csswg.org/css-font-lo…

致謝

感謝李鬆峯老師對本文提出的修改建議

相關文章
相關標籤/搜索