flexible.js字體大小詭異現象解析及解決方案

最近在作一個手機端頁面時,遇到了一個奇怪的問題:字體的顯示大小,與在CSS中指定的大小不一致。你們能夠查看這個Demo(記得打開Chrome DevTools)。html

Font Boosting Test

就如上圖所示,你能夠發現,本來指定的字體大小是24px,可是最終計算出來的倒是53px,看到這詭異的結果,我心中暗罵一句:這什麼鬼!git

隨後開始對問題各類排查:某個標籤引發的?某個CSS引發的?又或者是某句JS代碼引發的。經過一坨坨的刪代碼,發現貌似都不是。我不由又罵,到底什麼鬼!不過中間仍是發現了一些端倪:當頁面中的標籤數量或者文本數量大於某一個值,或者當CSS定義的字體大小落在某個區間時,這個問題纔會被觸發。並且字體變大後的值也隨着原始定義的字體大小而改變。github

而後天然就是各類搜索,終於有了新的發現。原來這個特性被稱作「Text Autosizer」,又稱「Font Boosting」、「Font Inflation」,是 Webkit 給移動端瀏覽器提供的一個特性:當咱們在手機上瀏覽網頁時,極可能由於原始頁面寬度較大,在手機屏幕上縮小後就看不清其中的文字了。而 Font Boosting 特性在這時會自動將其中的文字字體變大,保證在即不須要左右滑動屏幕,也不須要雙擊放大屏幕內容的前提下,也可讓人們方便的閱讀頁面中的文本。瀏覽器

不過這個特性並不老是有必要的,還好在查到問題緣由的同時,你們也討論了對這個問題的一些處理方案:ide

  1. 手動指定 viewport width=320,這時 Font Boosting 不會被觸發。(後邊能夠知道,這個說法不嚴謹,在其餘設置均爲默認值時,這一條纔有效)
  2. Font Boosting 僅在未限定尺寸的文本流中有效,給元素指定寬高,就能夠避免 Font Boosting 被觸發。
  3. 顯然第 2 條方案是有缺陷的,文本內容不可能都指定寬高。不過還好,咱們經過指定 max-height ,min-heightmin-widthmax-width(經 @Ovaldi 指正,只有 max-height 有效) 也是能夠的。好比body * { max-height: 999999px; } 就能夠無反作用的禁掉 Font Boosting 特性。固然,我以爲不必使用通用選擇器,用相似 p { max-height: 999999px; } 可能更好一些。

到這裏,咱們已經明白問題所在,而且也有解決方案了。可是有一個問題仍然困擾着我:當字體大於某一個值時(好比當不指定viewport width,手機屏幕width=320,字體大於等於82px時),這個 Font Boosting 就始終不會被觸發。Chrome 是如何計算的,這其中的邏輯又是什麼?字體

這一次問題解決起來就沒有那麼容易了,我先是各類搜索無果,而後本身人肉去試,慢慢找規律,可是發現變化不是線性的,看來這個公式還比較複雜。終於在今天被我發現了這篇文章:Chromium's Text Autosizer,完全解釋了個人疑問。google

Font Boosting 具體的實現代碼在 TextAutosizer.cpp 這個文件中能夠看到,有興趣的能夠翻一下。spa

簡單說來,Font Boosting 的計算規則僞代碼以下:debug

multiplier = Math.max(1, deviceScaleAdjustment * textScalingSlider * systemFontScale * clusterWidth / screenWidth); if (originFontSize < 16) { computedFontSize = originFontSize * multiplier; } else if (16 <= originFontSize <= (32 * multiplier - 16)) { computedFontSize = (originFontSize / 2) + (16 * multiplier - 8); } else if (originFontSize > (32 * multiplier - 16)) { computedFontSize = originFontSize; }

其中變量名解釋以下,更具體的說明能夠參考上邊的兩個連接。code

  • originFontSize: 原始字體大小
  • computedFontSize: 通過計算後的字體大小
  • multiplier: 換算係數,值由如下幾個值計算獲得
    • deviceScaleAdjustment: 當指定 viewport width=device-width 時此值爲 1,不然值在 1.05 - 1.3 之間,有專門的計算規則
    • textScalingSlider: 瀏覽器中手動指定的縮放比例,默認爲 1
    • systemFontScale: 系統字體大小,Android設備能夠在「設備 - 顯示 - 字體大小」處設置,默認爲 1
    • clusterWidth: 應用 Font Boosting 特性字體所在元素的寬度(如何肯定這個元素請參考上邊兩個連接)
    • screenWidth: 設備屏幕分辨率(DIPs, Density-Independent Pixels),如 iPhone 5 爲 320

說了這麼多,貌似只須要記住 p { max-height: 999999px; } 就OK了。。。-_-!!!

用 max-height: 100% 可能會更好一些。

 

WebKit 中應該有判斷若是initial-scale=1時,不觸發Font Boosting。

<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 或 --> <meta name ="viewport" content ="initial-scale=1, maximum-scale=1, minimum-scale=1">
相關文章
相關標籤/搜索