切換語言為:簡體
前端字型渲染閃爍?來試試預載入

前端字型渲染閃爍?來試試預載入

  • 爱糖宝
  • 2024-07-29
  • 2085
  • 0
  • 0

最近在做專案最佳化的時候偶然發現,我們做的頁面第一次進入字型會有一個閃爍的情況,這是什麼原因呢?下面來和大家仔細說說,先看效果

前端字型渲染閃爍?來試試預載入

閃爍問題原因?

其實這裏背後的原因 很簡單就是,我們沒有提前載入字型包,導致進入頁面使用到了字型然後進行網路請求,但由於網路請求需要一段時間向服務端獲取資源,這段時間前端頁面會使用預設字型,此時從預設字型轉化為請求的字型就出現閃爍。

前端字型渲染閃爍?來試試預載入

使用 css傳送網路請求載入字型

@font-face{
    font-family: 'JD-UDC-Bold';
    font-display: swap;
    src: url('./JD-UDC-Bold.otf')
}

以上程式碼應該比較容易理解,font-family 和  src 就不和大家講解了。

font-display 可選引數

```
/* 關鍵字值 */
font-display: auto;
font-display: block;
font-display: swap;
font-display: fallback;
font-display: optional;
```

屬性值 描述
auto 預設值。瀏覽器根據情況決定如何處理字型顯示。
block 在字型載入完成之前,使用佔位符進行顯示,避免文字閃現或導致佈局變化。
swap 在字型載入完成之前,使用與自定義字型相似的系統預設字型進行顯示,保持整體佈局的穩定性。
fallback 在字型載入完成之前,使用與自定義字型相似的系統預設字型進行顯示,並在載入完成後切換為自定義字型。
optional 優先顯示系統預設字型,在自定義字型在載入期間可用時切換為自定義字型。

如何解決 ?

在下給大家提供兩種方案

1:使用 JS 預載入 字型包

此方案也是當前生產上正在使用的方式,使用JS提供的內建API FontFace 進行請求

async loadFund () { 
    const fontList = ['JR-UDC-Bold.otf' , 'JR-UDC-Light.otf'] // 定義字型檔名稱
    for(const fontResolveUrL of fontList){ // 迴圈字型檔名稱
        if(typeof FontFace !==  'undefined'){ // 適配低版本 不支援 FontFace 的情況
            const fontInstance = new FontFace(fontResolveUrL.replace(/.otf/ , '') , `url(../fonts/${fontResolveUrL})`) // 如果瀏覽器支援 FontFace 則建立例項
            await fontInstance.load() // 開始載入字型
        }else{
            // 不相容 可以手動傳送一個 get請求 請求伺服器資源
        }
    }
}
setTimeout(loadFund , 500)// 使用 非同步載入不要影響頁面的FCP

以上程式碼 主要的邏輯時 以下幾點

  1. 定義非同步函式

  2. 迴圈載入字型

  3. 判斷瀏覽器是否支援FontFace ,不支援可以走 else 手動獲取 伺服器資源

當你使用 FontFace 物件載入的時候 , 其實內部 幫你傳送網路請求,獲取伺服器資源。

前端字型渲染閃爍?來試試預載入

FontFace 的引數

new FontFace('字型名稱' , 字型資源路徑 , 選項描述) 。

2:使用css載入 字型包

@font-face {
    font-family: 'MyFont';
    src: url('path/to/your/font.woff2') format('woff2'), 
    url('path/to/your/font.woff') format('woff'), 
    url('path/to/your/font.ttf') format('truetype'); 
    font-weight: normal; font-style: normal; 
}

總結

閃爍的問題來源於 字型沒有被載入,當被載入之後 css渲染解析時,可以直接獲取到資源,無需等待網路請求緩衝過程。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.