CSS @font-face性能優化

2021-02-20 IVWEB社區

本文主要介紹字體加載優化的常用策略,大部分內容為引用和翻譯。

一、 font-face基本用法

font-face的基本用法想必大家都是知道的,基本上就是類似這樣:

@font-face {    font-family: Lato;    src: url('font-lato/lato-regular-webfont.woff2') format('woff2'),       url('font-lato/lato-regular-webfont.woff') format('woff'),       url(font-lato/lato-regular-webfont.ttf) format("opentype");}
p { font-family: Lato, serif; }


這樣就可以使我們的網頁用上自定義字體了。 除了font-family 和 src屬性之外,還擁有font-style以及font-weight屬性。 src可以指定多種字體,會按順序依次適用,比如上面的示例中會先加載woff2字體,如果失敗再加載woff字體,否則加載opentype字體。 src所支持的字體可以有以下類型:

src參數帶不帶引號都可以,參數的格式不同含義也不盡相同,比如下面:

src: url(fonts/simple.woff);src: url(fonts/simple.woff);src: url(fonts/coll.otc#foo);src: url(fonts/coll.woff2#foo);src: url(fonts.svg#simple);


src中加載的字體地址受跨域的約束,如果想跨域加載字體,需要設置CORS。

這就是font-face的最基礎的用法。 接下來我們會進一步分析font-face的用法,並儘可能的找出優化策略。

二、 什麼時候會下載字體?

上面講了字體的基本知識,那你有沒有想過,字體是在什麼時候下載的呢?當我們僅僅在CSS中定義如下樣式的時候, 頁面加載,字體會自動下載嗎?

@font-face {  font-family: Lato;    src: url('font-lato/lato-regular-webfont.woff2') format('woff2'),       url('font-lato/lato-regular-webfont.woff') format('woff'),       url(font-lato/lato-regular-webfont.ttf) format("opentype");}


很遺憾,字體並不會下載。 通常情況下,只有當我們的頁面元素用到了font-face中定義的字體的情況下,才會下載對應的字體。

注意: 這裡我們說了是通常情況,這是因為,IE8在只要是定義了font-face,即使頁面元素沒有使用對應的字體,也會下載。

在其它瀏覽器中也不盡相同,

比如在Firefox 和 IE 9+ 中,遇到如下情況也會下載字體:



html

css

#test {  font-family: Lato;}


有什麼特別之處呢? 你可能注意到了,這個元素雖然使用到了font-family: Lato樣式,但是這個元素並沒有任何文本啊!!! 按照我們的理想情況,應該是,只有有文字內容才會去下載字體嘛。 而這就是Chrome, Safari (WebKit/Blink 等)瀏覽器的行為。

Chrome, Safari (WebKit/Blink 等)瀏覽器只有在如下類似情況才會去下載字體:



html

<div id="test">這裡是有文本的哦</div>

css

#test {  font-family: Lato;}



所以總結一下,不同瀏覽器下載字體的策略:

IE8 只要定義了font-face,就會去下載字體,不論實際有沒有應用該字體。

Firefox, IE 9+ 只有定義了font-face 並且頁面有元素應用了該字體,就會去下載,不論該元素是否有文本內容。

Chrome, Safari 只有定義了font-face 並且頁面有元素應用了該字體,並且該元素有文本內容,才會去下載字體。

那你可能會問了,如果我們的DOM元素是通過動態插入的呢?比如:

var el = document.createElement('div');el.style.fontFamily = 'open_sansregular';document.body.appendChild(el);el.innerHTML = 'Content.';

答案是一樣的,它的下載策略如下:

var el = document.createElement('div');el.style.fontFamily = 'open_sansregular';document.body.appendChild(el);el.innerHTML = 'Content.';


三、 FOIT(Flash of Invisible Text)

FOIT是瀏覽器在加載字體的時候的默認表現形式,也就是在字體加載過程中,頁面是看不到文本內容的。在現代瀏覽器中,FOIT會導致這種現象出現至多3秒。FOIT會導致很差的用戶體驗,這是我們需要儘量去避免的。

四、 FOUT(Flash of Unstyled Text) 與 font-display屬性

FOUT意思是在字體加載過程中使用默認的系統字體,字體加載完後顯示加載的字體,如果超過了FOIT(3s)字體還沒加載,則繼續使用默認的系統字體。

IE瀏覽器和Edge不會等待FOIT超時才顯示默認字體,會立即顯示默認字體。FOUT比FOIT好,但是需要注意它引起的reflow.

那麼要想使瀏覽器有FOUT行為,我們需要在設置@font-face的時候給它加一個屬性:font-display。 font-display默認是auto, 可選屬性與含義如下:

auto. The font display policy is user-agent-defined.

block. Gives the font face a short block period (3s is recommended in most cases) and an infinite swap period.

swap. Gives the font face an extremely small block period (100ms or less is recommended in most cases) and an infinite swap period.

fallback. Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases).

optional. Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a 0s swap period.

一般設置成fallback和optional即可。

五、 preload

在頁面加入下面這個代碼以便更快的加載字體:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

通常和最基本的字體用法配合使用

六、 字體轉 BASE64URI

這種方法就是將@font-face中定義字體時的路徑直接改為字體的base64編碼。

優點: 這種做法的優點是不會產生FOIT和FOUT。所以也不會有reflow和repaint. 

缺點: 字體轉成base64也會很大,會影響頁面首次加載速度。不支持逗號分隔的形式加載多種格式的字體,只能加載一種格式字體。這導致你為了儘可能保證所有瀏覽器都可以兼容,通常會指定為woff格式,因為woff格式兼容性好,但是卻沒法使用更小體積的woff2格式,因為woff2格式兼容性差點。

七、異步加載BASE64格式URI字體

這種方法就是通過異步的方式插入帶有BASE64格式URI字體的CSS連結。

八、使用Font Load API + FOUT + class切換

這種方式起初並不使用@font-face的class,而是用Font Load API加載我們想用的字體,然後切換相應的CSS即可。Font Load API是原生的API:

document.fonts.load('1em open_sansregular').then(function() {  var docEl = document.documentElement;  docEl.className += ' open-sans-loaded';});

.open-sans-loaded h1 {  font-family: open_sansregular;}


當然這種方法需要考慮瀏覽器兼容性的問題。

九、 FOFT(Flash of Faux Text)

FOFT會把字體的加載分成多個部分,首先加載羅馬網絡字體,然後會在加載真實的粗體和斜體的時候立即使用font-synthesis屬性渲染粗體和斜體的變體。

這種方法是基於[使用Font Load API + FOUT + class切換]這種方式的,非常適合加載同一種字體但是不同粗細,字形的場景,比如羅馬、粗體、斜體、粗斜體等。我們將這些字體分成2階段: 第一階段是羅馬字體,然後立即渲染人造粗體和斜體,最後(第二階段)用真實字體替代。這裡面還可以使用sessionStorage優化訪問重複視圖的場景。

十、CRITICAL FOFT

CRITICAL FOFT和標準的FOFI的唯一區別就在於第一階段羅馬字體的加載,CRITICAL FOFT不會加載羅馬字體的全集,只會加載它的一個子集(比如A-Za-z0-9),全集會在第二階段加載。

十一、CRITICAL FOFT WITH DATA URI

這個和CRITICAL FOFT的唯一區別就是羅馬子集字體的加載方式,前面是用Font Load API完成了,這裡會將馬子集字體硬編碼成BASE64 URI的形式加載。

十二、 CRITICAL FOFT WITH PRELOAD

這個同上面的唯一區別還是第一階段羅馬子集字體的加載方式,它採用的是preload的形式加載。

結論

總的字體加載的策略可以用這個圖總結如下:

參考文獻

本文主要翻譯自如下博客文章

相關焦點

  • 前端引用字體@font-face的若干優化方法
    😂 獻醜了 😂2、 正 文2.1 本地字體2.1.1 版 權首先一定要注意這個問題2.1.2 字體定義一般情況定義如下:@font-face { font-family:"Regular"; src:url
  • Web 性能優化:使用 CSS font-display 控制字體加載和替換
    後來,CSS 開始支持 @font-face 這個指令,可以加載自定義的字體文件,這個時候可以把字體隨網站一起發布,用戶在瀏覽網站的時候,會下載 @font-face 中指定的字體。例如下邊的代碼加載了 fonts 目錄下的 Raleway 字體:@font-face {  font-family: 'Raleway';  font-style: normal;  font-weight: 500;  src: url(/fonts/raleway.woff2) format('woff2
  • CSS3 icon font完全指南
    大家都知道現在各個瀏覽器都支持CSS3的自定義字體(@font-face),包括IE6都支持,只是各自對字體文件格式的支持不太一樣。比如,twitter用到的各種小icon:這種情況下,使用字體來實現圖標就有很多優勢:字體文件小,一般20-50kb;容易編輯和維護,尺寸和顏色可以用css來控制;透明完全兼容IE6;如何將icon變成字體?最關鍵的是要將設計稿中的icon(要有矢量路徑,位圖沒法轉化)完美還原成字體,這並不是很麻煩。
  • 自定義字體@font-face的常見應用
    基本用法如下:@font-face { font-family: "family-name"; src: url("family-name.eot"); src: url("family-name.eot?
  • 真正了解 CSS3 背景下的 @font face 規則
    話是沒錯,問題在於很多人就以為生成字符小圖標就是@font face規則的全部,實際上只是功能之一,如果真正了解@font face規則,你會發現,@font face規則可以做的事情其實非常多,尤其我們不考慮IE7,IE8瀏覽器的情況下。
  • 聊一聊「@font-face」
    首先先了解關於@font-face的基本知識1、@font-face 與 EOT 格式之所以把它們放到一起是因為首個實現@font-face 和 EOT 的是同一家公司 - 微軟。當時的系統用一種簡單的灰階反鋸齒技術,對於系統的字體這足夠了,但對於其他字體,由於缺少人工的優化,字體會變得很虛。因此,本來想改進網頁的排版效果,結果卻使文字都無法閱讀。於是,CSS2.1 中徹底去掉了 @font-face 語法也不足為奇了。
  • 博客性能優化
    上次將博客託管到 Vercel 之後訪問速度有了很大改善,於是就想深入做一些優化,這是本次優化過後 LightHouse 的評分:除了性能改善,還修復了所有的 Accessibility 問題,我希望能最終構建出一個美觀、簡單、對 SEO 友好且快速的博客,下面就來說說本次優化的具體內容
  • Web 性能優化:控制關鍵請求的優先級
    前言ByteDance Web Infra 團隊裡面有兩個方向專門關注前端性能,分別從代碼和監控對性能優化有很深入的研究。性能優化有很多角度,其中一個關鍵是控制關鍵請求的優先級,從而達到性能優化的效果。本文以一種相對系統的方式來進行該方法的探討。也歡迎有興趣的讀者關注我們,和我們進行交流。
  • 僅使用CSS提高頁面渲染速度
    之後,它將該元素的渲染與其他優化一起委託給GPU,即,瀏覽器會識別will-change屬性,並優化未來與不透明相關的變化。這將使動畫變得更加流暢,因為GPU加速接管了動畫的渲染。,因為它會遍歷整個DOM樹(在本例中,DOM樹很大,因為它有10000個DOM元素):
  • 【Hello CSS】第一章-CSS的語法與工作流
    -- style.css -->h1 {color:red; font-size:14px;}<!-- index.html --><!{ system: fixed; symbols: Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ; suffix: " ";}.items { list-style: circled-alpha;}@font-face
  • PostCSS (一):認識 PostCSS
    它可以作為一款 CSS 前置處理器( preprocessor ) 使用, 就像 Sass 和 Less 等一樣,使用 postcss-simple-vars, postcss-mixins, postcss-nested, postcss-sass-extend 等插件來實現 Sass 提供的 變量, mixin,選擇器嵌套,extend 等功能。
  • 項目WebFont優化
    「 WebFont優化是總體性能優化策略的一個關鍵部分。
  • css font的簡寫規則
    css font的簡寫規則,新鮮出爐,趕快記住你把!一、字體屬性主要包括下面幾個font-family,font-style,font-variant,font-weight,font-size,fontfont-family(字體族): 「Arial」、「Times New Roman」、「宋體」、「黑體」等;font-style
  • CSS 渲染原理以及優化策略
    我們先來看看這張排行榜:css渲染原理既然 CSS 這麼重要,那麼我們花點時間來研究相關原理也就物有所值了。本節我們就來說說 CSS 渲染以及優化相關的內容,主要圍繞以下幾點,由淺入深,了解來龍去脈:瀏覽器構成
  • 如何優化 CSS WebFont 加載速度 ?
    一般應用 Web Font 的流程是這樣的:創建一個 CSS 文件,其中定義 @font-face, 接著通過一個 link 標籤引入 CSS ,樣式就可以使用這個定義好的字體了。通常情況下,我們都是這麼做的,各種材料書刊也是這麼教的。但是,如果此時你打開 Lighthouse,可能會發現 Lighthouse 給出了一些優化建議。  怎麼回事,是哪裡出問題了?
  • 【CSS】886- 你該知道的字體 font-family
    system-ui簡單而言,font-family: system-ui 的目的就是在不同的作業系統的 Web 頁面下,自動選擇本作業系統下的默認系統字體。默認使用特定作業系統的系統字體可以提高性能,因為瀏覽器或者 webview 不必去下載任何字體文件,而是使用已有的字體文件。
  • 網絡字體@font-face 如何處理網頁中的特殊字體
    而且用圖片代替文字的做法,並不方便修改,也不利於SEO搜尋引擎優化(譬如LOGO使用了h1標籤,卻由於字體很特殊而使用了圖片,那麼h1的作用基本等同於沒有發揮出來)。在CSS2.0 規範中有一個東西,@font-face(IE4.0就存在),後來在 CSS2.1 草案中又被刪掉。後來又被納入到CSS3草案當中。這個東西就是今天要跟大家分享的東西——自定義網絡字體。
  • 瀏覽器渲染原理與性能優化
    網絡進程:主要處理網絡資源加載(HTML、CSS,、JS等)GPU進程:3d繪製,提高性能插件進程:chrome中安裝的一些插件二.從輸入URL到瀏覽器顯示頁面發生了什麼?用戶輸入的是關鍵字還是URL?
  • 【Web API 教程】— FontFace API
    family:字符串,表示字體名,寫法與 CSS 的@font-face的font-family屬性相同。source:字體文件的 URL(必須包括 CSS 的url()方法),或者是一個字體的 ArrayBuffer 對象。descriptors:對象,用來定製字體文件。該參數可選。
  • 性能優化必知preload 和 prefetch
    今天我們來探索一下前端資源的一些指令以及它們如何來提高網站性能的