web安全字體

 

webfont解剖

  • Unicode字體能夠包含數以千計字形
  • 有四個字體格式: WOFF2, WOFF, EOT, TTF
  • 一些字體格式須要使用GZIP壓縮 

一個web字體是字形的集合,且每一個字形是一個描述了一個字母亦或符號的矢量圖。css

因此,一個字體文件的大小由兩個因素決定:每一個字形矢量路徑的複雜程度和每一個字體所包含的字形數量。css3

例如,Open Sans, 最流行的web字體之一, 包含了897個字形,包含了拉丁,希臘和古代斯拉夫語字母。git

Font glyph table

當選擇一個字體的時候,重要的是考慮哪些字符集被支持。github

例如, Google’s Noto font family 目標是支持世界上全部的語言. 可是,注意Noto的大小,由於包括了全部的語言,因此壓縮後大小是130MB+。web

Web字體格式

網上現在四個web字體格式: EOTTTFWOFF, 和 WOFF2.算法

不幸的是,雖然有不少的選擇,可是沒有一個字體是能夠在舊的瀏覽器和新的瀏覽器上通用的:EOT只適用於IE,TTP部分被IE支持。WOFF享有最普遍的支持可是在老的瀏覽器中沒必要支持,而且對於不少新的瀏覽器真在添加對於WOFF 2.0的支持。編程

因此,這意味着咱們須要使用多個字體格式來保持良好的用戶體驗:api

  • 在支持WOFF 2.0的瀏覽器中使用WOFF 2.0 變體
  • 在大多數瀏覽器中使用WOFF字體
  • 在老的安卓(低於4.4)瀏覽器中使用TTF變體
  • 在老的IE(低於IE9)中使用EOT變體 

使用壓縮來減小字體大小

A font is a collection of glyphs, each of which is a set of paths describing the letter form. The individual glyphs are, of course, different, but they nonetheless contain a lot of similar information that can be compressed with GZIP, or a compatible compressor:瀏覽器

  • EOT, 和 TTF 格式默認沒有壓縮:確保你的服務器使用了GZIP壓縮 
  • WOFF 有內置的壓縮 - 確保你的WOFF壓縮器使用了最優化的設置。
  • WOFF2 使用了用戶預約義和壓縮算法來減小相對於其餘字體格式約30%的文件大小

值得注意的是一些字體格式包括了額外的信息——好比font hitting和kerning信息,這些多是沒必要要的,因此能夠進行深刻優化。緩存

查看你的字體編譯器可操做的選項,若是你能夠優化上面的內容,進行優化,並在不一樣的瀏覽器中查看效果。

Note

  • 可使用 Zopfli compression 來壓縮EOT, TTF,和 WOFF 字體格式. Zopfli 是一個 zlib兼容的壓縮器,壓縮的內容比gzip壓縮後還要小約5%。

使用 @font-face定義字體

  • 使用format()定義不一樣的字體格式
  • 使用大量的子集提升性能: 提供大量可選的子集可讓舊的瀏覽器兼容 
  • 減小樣式化的字體變體來提升頁面和文字渲染效果 

 css語句@font-face定義特殊的字體資源的位置,字體樣式等。

字體樣式選擇

每一個 @font-face 聲明提供了font family的名字,字體屬性的什麼和特殊字體來源地址的聲明。

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome.woff2') format('woff2'), 
       url('/fonts/awesome.woff') format('woff'),
       url('/fonts/awesome.ttf') format('ttf'),
       url('/fonts/awesome.eot') format('eot');
}

@font-face {
  font-family: 'Awesome Font';
  font-style: italic;
  font-weight: 400;
  src: local('Awesome Font Italic'),
       url('/fonts/awesome-i.woff2') format('woff2'), 
       url('/fonts/awesome-i.woff') format('woff'),
       url('/fonts/awesome-i.ttf') format('ttf'),
       url('/fonts/awesome-i.eot') format('eot');
}

 

上面一個 Awesome Font 字體的兩個表現形式類型:正常和斜體,每一個都提供了一系列的不一樣字體資源設置。

每一個src描述符包括了一個按照優先順序排序的,用逗號進行分隔的資源列表:

  • local() 代表咱們可使用哪些本地的字體 
  • url() 指定咱們加載哪些外部字體,容許咱們使用format()來指代字體的格式 

Note

  • 除非你指向系統的默認資源,除非不多有本地的字體資源,特別是對手機設備而言,不可能在內部安裝了額外的字體。因此,你老是須要提供一個額外的字體位置清單。

瀏覽器按照順序執行,上例瀏覽器執行以下:

  1. 瀏覽器顯示頁面佈局並決定哪一個字體變形被須要來渲染指定的字體;
  2. 依次檢查local()中的字體是否存在並可以使用; 
  3. 若是本地不存在,依次檢查外部字體定義:
    • 若是字體格式存在,在初始化和下載字體之間檢查瀏覽器是否支持,若是不支持,進入下一個外部字體選項檢查 
    • 若是字體格式不存在,瀏覽器下載資源 

Note

  • 外部字體加載的順序十分重要,由於瀏覽器是按照這個順序依次執行的。

Unicode-range 子集

咱們能夠將一個大的字體設置成小的子集(例如拉丁,希臘和斯拉夫字母等),而且只是加載這個子集來渲染頁面上的字體

 

這個 unicode-range descriptor 容許咱們指定一個逗號隔開的數據集合, 數據能夠是下面三種形式中的任何一種:

  • Single codepoint (e.g. U+416)
  • Interval range (e.g. U+400-4ff): indicates the start and end codepoints of a range
  • Wildcard range (e.g. U+4??): ‘?’ characters indicate any hexadecimal digit

例如咱們能夠將Awesome Font設置成拉丁和日本語的子集格式,它們只有在瀏覽器須要的時候纔會加載 

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2'), 
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('ttf'),
       url('/fonts/awesome-l.eot') format('eot');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-jp.woff2') format('woff2'), 
       url('/fonts/awesome-jp.woff') format('woff'),
       url('/fonts/awesome-jp.ttf') format('ttf'),
       url('/fonts/awesome-jp.eot') format('eot');
  unicode-range: U+3000-9FFF, U+ff??; /* Japanese glyphs */
}

Note

  • Unicode-range子集設置對於亞洲語言很是重要,由於亞洲語言的字形比西方語言要多得多,一個字形百萬字節,而不是亞洲字符的千字節。

使用unicide range子集並將文件分紅字體不一樣樣式的變體讓咱們能夠更加迅速和高效的下載——用戶只須要下載子集和變體就能夠,用戶不須要下載永遠不會用到的字體。

可是,不是全部的瀏覽器支持unicode-range字段。一些瀏覽器忽略了unicode-range字段,而且將下載全部的字體;另外一些瀏覽器壓根兒不會執行@font-face聲明。因此,咱們對於舊的瀏覽器須要「手動設置子集」。

由於舊的瀏覽器不夠聰明來選擇須要的字體子集而且不能合成一個合適的字體,因此咱們必須回退來提供一個單一的字體資源,這個字體資源包括了全部必要的子集,而且對瀏覽器而言隱藏了其餘的子集。

例如,若是網頁只是使用拉丁文子集。咱們能夠剝奪其餘的字形,而且將一個指定的子集設置成單獨的資源。

  1. 咱們怎樣判斷哪些字體子集是咱們須要的?
    • 若是unicode-range子集是被瀏覽器支持的,那麼瀏覽器就會在自動的選擇合適的子集,頁面只須要提供子集文件和在@font-face指定合適的unicode-ranges
    • 若是unicode-range不是瀏覽器支持那麼頁面須要隱藏全部沒必要要的子集——例如,開發者必須指定須要的子集。
  2. 咱們在什麼樣的狀況下創造子集?
    • 使用開源工具 pyftsubset tool 來設置和最優化你的子集.
    • 一些字體提供商容許你在用戶自定義參數中手動設置字體子集,你能夠經過這個方法來手動的爲你的頁面建立須要的字體——訪問字體提供商的頁面!

字體選擇和合成

每一個字體家族都是包含不少樣式的字體變體(例如常規,加粗,斜體等等),而且每一種字體變體都有字體權重設置,因此,這將致使了不少不一樣的字形——例如,不一樣空格,字體大小都將致使同一個字形變得不一樣。

Font weights

例如,上面的圖形展現了一個字體在三種不一樣的權重下的表現:400(普通),700(加粗),900(額外加粗)。

全部的在三個標準之間的權重(灰色顯示的)將經過瀏覽器自動的適應最貼近的三種標準變體。


上述邏輯一樣適用於斜體字體,可是要記住,字體變形數量使用越少越好!

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2'), 
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('ttf'),
       url('/fonts/awesome-l.eot') format('eot');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 700;
  src: local('Awesome Font'),
       url('/fonts/awesome-l-700.woff2') format('woff2'), 
       url('/fonts/awesome-l-700.woff') format('woff'),
       url('/fonts/awesome-l-700.ttf') format('ttf'),
       url('/fonts/awesome-l-700.eot') format('eot');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

 

上面的例子聲明瞭一個 Awesome Font 家族字體,包含了拉丁字形,可是擁有兩種不同的權重:normal(400)和blod(700)。字體不一樣的形式實現的原理是什麼呢?

  • 若是給出的字體權重不是標準的(400,700和900),那麼將隨瀏覽器匹配最接近標準的字體形式。
  • 若是字體斜體匹配沒有發現(例如,咱們沒有在上例中聲明任何的斜體變形),那麼瀏覽器近合成它的自有的字體變形。

Font synthesis

必需要知道的是,有些字體經過合成的方法合成的字體會十分難看(好比Cyrillic合成斜體),因此最好使用已經存在的斜體,而不是瀏覽器自動合成。

上面的例子解釋了實際斜體和瀏覽器合成的斜體之間的不一樣(字體是Open-Sans字體)。

你能夠在結果中看見顯著的不一樣,不一樣的瀏覽器合成字體不一樣而且不一樣的字體之間合成的字體也不一樣。

Note

  • 爲了最好的用戶體驗,咱們應該儘可能不要使用字形變體,咱們最好指定字體的位置讓頁面來下載它們。總而言之,使用瀏覽器合成的變體必須很是當心。

優化下載和渲染

  • 字體加載請求會在渲染樹(the render tree)被建立以後,這可能致使字體渲染被延遲。
  • 字體加載API一樣也容許咱們實現用戶自定義的字體加載和渲染政策來重寫和替代默認的字體延遲加載
  • Font inlining 容許咱們在舊的瀏覽器中從新書寫字體加載形式

一個完整的web字體包含了全部形式的變體,和全部的字形,可是有些字形和字體的變體咱們可能不須要,致使下載完整的web字體須要多個百萬字節。

因此使用@font-face是咱們能夠加載指定範圍的web字體,使用unicode 子集,獨特的字體變形等等。

給出這些申明後瀏覽器能夠加載指定的字體來進行渲染,雖然很方便,可是若是咱們不當心的話,會致使在渲染時產生障礙——這些是咱們須要避免的!

web字體渲染方式

咱們知道字體的渲染必須在瀏覽器建立了渲染樹(就是DOM樹和CSSOM樹)以後,因此,也就是說字體渲染必須等到全部的資源都被抓取以後

Font critical rendering path

  1. 瀏覽器情趣HTML2文檔
  2. 瀏覽器開始解析HTML響應和構造DOM
  3. 瀏覽器你發現CSS,JS和其餘的資源而且分配請求 
  4. 當全部的css內容都被接受而且將其和DOM樹結合在一塊兒以後構建CSSOM。
    • 當樹DOM樹被渲染的時候字體被請求,說明了字體變體被渲染到指定的文本上。
  1. 瀏覽器將佈局展示在屏幕上面
    • 若是瀏覽器不能夠得到字體嗎,那麼將不會渲染任何的文本像素
    • 一旦瀏覽器能夠得到字體,瀏覽器將會渲染文本像素

不一樣的瀏覽器在渲染的時候執行的操做不同:

  • Safari 在文本下載所有完成以後才進行文本渲染
  • Chrome 和 Firefox 在你使用一個回退字體時,進行三秒鐘的字體渲染, 而且一旦字體下載完成,瀏覽器用剛下載的字體再次進行渲染
  • IE立刻渲染回退字體若是請求的字體不可得到,而且一旦字體加載所有完成以後在進行再次渲染 。

不一樣的人有不一樣的喜愛——有些人喜歡立刻進行渲染有些人喜歡在回退字體加載後進行再次渲染——咱們不作任何的評論,可是咱們關注的是在佈局加載時進行的字體渲染怎樣才能進行優化?

使用字體下載API來優化字體渲染

Font Loading API 提供了一個編程腳原本定義和操做CSS字體,追蹤字體的下載進程和重寫字體的懶加載行爲(懶加載是指在DOM樹和CSSOM樹加載完成以後才進行字體加載渲染的行爲)。

例如,若是咱們確保一個特殊的字體變形會被請求,咱們能夠定義它而且告訴瀏覽器來初始化即時加載字體資源行爲:

var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
  style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});

font.load(); // don't wait for render tree, initiate immediate fetch!

font.ready().then(function() {
  // apply the font (which may rerender text and cause a page reflow)
  // once the font has finished downloading
  document.fonts.add(font);
  document.body.style.fontFamily = "Awesome Font, serif";

  // OR... by default content is hidden, and rendered once font is available
  var content = document.getElementById("content");
  content.style.visibility = "visible";

  // OR... apply own render strategy here... 
});

 

並且,由於咱們能夠檢查字體的狀態(font status)經過check()方法,而且追蹤下載的速度,咱們一樣能夠定義一個自定義的策略來在咱們的頁面上渲染文本,

  • 咱們能夠知道字體可使用時才渲染全部文本 
  • 咱們能夠對於每個字體設置定時器timeout 

咱們能夠在不一樣的頁面上使用不一樣的策略。

Note

使用inlining來優化渲染字體

  • 在構建CSSOM對象的時候,css樣式中匹配設備的查詢將做爲首選自動加載 
  • 將字體數據嵌入css樣式表中將強制瀏覽器來加載字體,而且以高優先級進行不用等到渲染樹的完成

可是 inlining策略不夠靈活而且不容許針對不一樣個頁面咱們來定義用戶自定義的定時器和渲染策略。爲了最好的效果,將你的嵌入字體數據的css獨立成css文件,而且加載的時候設置max-age屬性,這樣當你更新css文件的時候不用強迫你的用於再次下載你的字體。

Note

  • 使用inlining策略! 記得上面說的懶加載麼?瀏覽器一般都是在加載DOM和造成CSSOM對象以後,造成渲染樹以後在渲染數據內容到屏幕上的!將字體數據放在CSS中,也就是放在CSSOM對象造成之時!

使用HTTP緩存優化你的字體再使用

字體資源是靜止的資源,因此能夠再次使用,使用http緩存,爲字體設置較長時間的max-age。沒有必要將字體存儲在localStorage中,這會影響性能。

優化總結列表

使用web字體除了會進行下載和下載沒必要要的資源以外,不會影響頁面的渲染和性能!因此放心大膽使用,下面是一些優化建議:

  1. 審查和監聽你的字體: 每一個網頁中不要使用太多的字體,每一個字體都要簡化它們的變體數量。
  2. 使用字體資源中的子集: 沒有必要下載整個字體資源,使用特定的字體子集。特別是對於亞裔字體而言,必定要加載子集。
  3. 對每一個瀏覽器而言使用最優化的字體格式: 每一個字體都應該提供 WOFF2, WOFF, EOT, 和 TTF的字體格式. 確保對 EOT 和 TTF進行GZIP壓縮,由於默認它們是沒有進行壓縮的
  4. 使用緩存策略: 字體資源是靜態的,因此記得使用max-age來設置http緩存
  5. 使用字體加載API來制定字體渲染方式: 默認的加載方式是字體最後渲染,字體加載API容許咱們重寫對於特定字體的渲染行爲,對於不一樣的網頁咱們能夠自定義渲染方式亦或設置一個定時器策略。對於舊的不支持字體加載API的瀏覽器,咱們可使用webfontloader的js庫亦或使用css嵌入策略。
相關文章
相關標籤/搜索