H5 移動端開發基礎知識

2022-01-28 前端試煉

👆  點擊上方卡片關注

本文是內部的一次分享沉澱,偏向基礎但是涉及了一些有意思的細節,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

前端的一大工作內容就是去兼容頁面在不同內核的瀏覽器,不同的設備,不同的解析度下的行為,使頁面的能正常工作在各種各樣的宿主環境當中。

而本文的主題 -- 移動端開發的兼容適配與性能優化,就是希望能從一些常見的移動端開發問題出發,釐清 Web 移動端開發的前前後後,一些技術的發展過程,一些問題的優化手段以及給出一些常見的兼容性問題的解決方案。

什麼是響應式設計

首先先聊聊響應式設計,這個與移動端開發有著密切的聯繫。

響應式設計即是 RWD,Responsive Web Design。

這裡百度或者谷歌一下會有各種各樣的答案。這裡一段摘自知乎上我覺得很棒的一個答案:什麼是響應式布局設計?[1]

根據維基百科及其參考文獻,理論上,響應式界面能夠適應不同的設備。描述響應式界面最著名的一句話就是「Content is like water」,翻譯成中文便是「如果將屏幕看作容器,那麼內容就像水一樣」。

為什麼要設計響應式界面

為什麼要費神地嘗試統一所有設備呢?

即便是 PC 或 Mac 用戶,有數據顯示只有一半的人會將瀏覽器全屏顯示,而剩下的一般人使用多大的瀏覽器,很難預知;臺式機、投影、電視、筆記本、手機、平板、手錶、VR……智能設備正在不斷增加,「主流設備」的概念正在消失;屏幕解析度正飛速發展,同一張圖片在不同設備上看起來,大小可能天差地別;滑鼠、觸屏、筆、攝像頭手勢……不可預期的操控方式正在不斷出現。響應式界面的四個層次同一頁面在不同操作方式(如滑鼠和觸屏)下,體驗應該是統一的;同一頁面在不同類型的設備(手機、平板、電腦)上,交互方式應該是符合習慣的。響應式界面的基本規則

可伸縮的內容區塊:內容區塊的在一定程度上能夠自動調整,以確保填滿整個頁面

可自由排布的內容區塊:當頁面尺寸變動較大時,能夠減少/增加排布的列數

適應頁面尺寸的邊距:到頁面尺寸發生更大變化時,區塊的邊距也應該變化

能夠適應比例變化的圖片:對於常見的寬度調整,圖片在隱去兩側部分時,依舊保持美觀可用

能夠自動隱藏/部分顯示的內容:如在電腦上顯示的的大段描述文本,在手機上就只能少量顯示或全部隱藏

能自動摺疊的導航和菜單:展開還是收起,應該根據頁面尺寸來判斷

放棄使用像素作為尺寸單位:用dp(對於前端來說,這裡可能是rem)尺寸等方法來確保頁面在解析度相差很大的設備上,看起來也能保持一致。同時也要求提供的圖片應該比預想的更大,才能適應高解析度的屏幕

上面一段我覺得已經涵蓋了響應式設計的絕大部分,簡單總結起來,可以概括為:

媒體查詢,邊界斷點的規則設定(Media queries && break point)內容的可伸縮性效果(Flexibel visuals)主要內容呈現及圖片的高質量(Main content and high quality)響應式 vs. 自適應

響應式設計是 Responsive Web Design(RWD),自適應設計是 Adaptive Web Design(AWD)。經常有人會將兩者混為一談,或者其實根本也區分不了所謂的響應式與自適應。

其實在我寫這篇文章的時候,我也無法很好的去區分兩者。

RWD 和 AWD 兩者都是為了適配各種不同的行動裝置,致力於提升用戶體驗所產生的的技術。核心思想是用技術來使網頁適應從小到大(現在到超大)的不同解析度的屏幕。通常認為,RWD 是 AWD 的子集

RWD:Ethan Marcote 的文章是大家認為 RWD 的起源。他提出的 RWD 方案是通過 HTML 和 CSS 的媒體查詢技術,配合流體布局實現。RWD 傾向於只改變元素的外觀布局,而不大幅度改變內容。Jeffrey Zeldman 總結說,我們就把 RWD 定義為一切能用來為各種解析度和設備性能優化視覺體驗的技術

AWD:Adaptive Design 是 Aaron Gustafson 的書的標題。他認為 AWD 在包括 RWD 的 CSS 媒體查詢技術以外,也要用 Javascript 來操作 HTML 來更適應行動裝置的能力。AWD 有可能會針對移動端用戶減去內容,減去功能。AWD 可以在伺服器端就進行優化,把優化過的內容送到終端上。

一圖勝千言。

image

從定義上而言,RWD 是一套代碼,適用於所有屏幕。而 AWD 則是多端多套代碼。本文不會過多去糾結響應式與自適應區別,我覺得這兩者的本質都是致力於適配不同設備,更好地提升用戶體驗。

Quora - Responsive Design vs. Adaptive Design?[2]zhihu -- Responsive design 和 Adaptive design 的區別[3]

漸進增強 vs. 優雅降級

漸進增強(progressive enhancement):針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。

優雅降級(graceful degradation):一開始就構建完整的功能,然後再針對低版本瀏覽器進行兼容。

區別:優雅降級是從複雜的現狀開始,並試圖減少用戶體驗的供給,而漸進增強則是從一個非常基礎的,能夠起作用的版本開始,並不斷擴充,以適應未來環境的需要。降級(功能衰減)意味著往回看;而漸進增強則意味著朝前看,同時保證其根基處於安全地帶。

漸進增強/優雅降級通常是 AWD 會牽扯到的另一個技術術語。本質上而言即是隨著屏幕的大小的改變,功能會一點一點增強。

也通常會用在一些高級 CSS3 屬性上,我們對一些 CSS 屬性進行特性檢測,甚至不進行特性檢測直接使用。後果是在支持它的網頁上該屬性正常展示,而不支持它的網頁該屬性不生效,但也不影響用戶的基本使用。

典型的例子是 CSS3 逐漸被大眾認可並被使用,PC端頁面開始由 IE678 向兼容性更好的IE9+,chrome,firefox瀏覽器轉變的時期。我們可以對頁面元素直接使用陰影,圓角等屬性。對於不支持它的低版本 IE 而言,沒有什麼損失,而對於支持它的高級瀏覽器而言,帶給了用戶更好的交互視覺體驗,這就是漸進增強。

移動端屏幕適配方案

下面會針對一些具體的案例,展開講講。第一個是高保真還原設計稿,也就是如何適配移動端繁雜的屏幕大小。

通常而言,設計師只會給出單一解析度下的設計稿,而我們要做的,就是以這個設計稿為基準,去適配所有不同大小的移動端設備。

在此之前,有一些基礎概念需要理解。

一些概念性的東西,大部分人很難一次性記住,或者記了又忘,我覺得記憶這個東西比較看技巧,比如關聯法,想像法,把這些生硬的概念與一些符合我們常識的知識關聯在一起記憶,往往能夠事半功倍。

設備獨立像素

以 iPhone6/7/8為例,這裡我們打開 Chrome 開發者工具:

image

這裡的 375 * 667 表示的是什麼呢,表示的是設備獨立像素(DIP),也可以理解為 CSS 像素,也稱為邏輯像素:

設備獨立像素 = CSS 像素 = 邏輯像素

如何記憶呢?這裡使用 CSS 像素來記憶,也就是說。我們設定一個寬度為 375px 的 div,剛好可以充滿這個設備的一行,配合高度 667px ,則 div 的大小剛好可以充滿整個屏幕。

物理像素

OK,那麼,什麼又是物理像素呢。我們到電商網站購買手機,都會看一看手機的參數,以 JD 上的 iPhone7 為例:

image

可以看到,iPhone7 的解析度是 1334 x 750,這裡描述的就是屏幕實際的物理像素。

物理像素,又稱為設備像素。顯示屏是由一個個物理像素點組成的,1334 x 750 表示手機分別在垂直和水平上所具有的像素點數。通過控制每個像素點的顏色,就可以使屏幕顯示出不同的圖像,屏幕從工廠出來那天起,它上面的物理像素點就固定不變了,單位為pt。

設備像素 = 物理像素

DPR(Device Pixel Ratio) 設備像素比

OK,有了上面兩個概念,就可以順理成章引出下一個概念。DPR(Device Pixel Ratio) 設備像素比,這個與我們通常說的視網膜屏(多倍屏,Retina屏)有關。

設備像素比描述的是未縮放狀態下,物理像素和設備獨立像素的初始比例關係。

簡單的計算公式:

DPR = 物理像素 / 設備獨立像素

我們套用一下上面 iPhone7 的數據(取設備的物理像素寬度與設備獨立像素寬度進行計算):

iPhone7’s DPR = iPhone7’s 物理像素寬度 / iPhone7's 設備獨立像素寬度 = 2

750 / 375 = 2或者是 1334 / 667 = 2

可以得到 iPhone7 的 dpr 為 2。也就是我們常說的視網膜屏幕。

視網膜(Retina)屏幕是蘋果公司"發明"的一個營銷術語。蘋果公司將 dpr > 1 的屏幕稱為視網膜屏幕。

image

在視網膜屏幕中,以 dpr = 2 為例,把 4(2x2) 個像素當 1 個像素使用,這樣讓屏幕看起來更精緻,但是元素的大小本身卻不會改變:

image

OK,我們再來看看 iPhone XS Max:

它的物理像素如上圖是 2688 x 1242,

image

它的 CSS 像素是 896 x 414,很容易得出 iPhone XS Max 的 dpr 為 3。

上面三個概念(CSS像素、設備獨立像素、DPR)是我覺得比較重要的,還有一些其他比較重要的概念 PPI、DPI 不影響後續的內容,可以自行去加深理解。

OK,到這裡我們就完成了一個小的裡程碑。我們通常說的H5手機適配也就是指的這兩個維度:

適配不同屏幕大小,也就是適配不同屏幕下的 CSS 像素適配不同像素密度,也就是適配不同屏幕下 dpr 不一致導致的一些問題適配不同屏幕大小

適配不同屏幕大小,也就是適配不同屏幕下的 CSS 像素。最早移動端屏幕 CSS 像素適配方案是CSS媒體查詢。但是無法做到高保真接近 100% 的還原。

適配不同屏幕大小其實只需要遵循一條原則,確保頁面元素大小的與屏幕大小保持一定比例。也就是:按比例還原設計稿

假設我們現在拿到標註為 375*667 的大小的設計稿,其中一個元素的標註如下:

以頁面寬度為基準的話,那麼,

這樣,無論屏幕的 CSS 像素寬度是 320px 還是 375px 還是 414px,按照等量百分比還原出來的界面總是正確的。

然而,理想很豐滿,現實很骨感。實現上述百分比方案的核心需要一個全局通用的基準單位,讓所有百分比展示以它為基準,但是在 CSS 中,根據CSS Values and Units Module Level 4[4]的定義:

百分比值總要相對於另一個量,比如長度。每個允許使用百分比值的屬性,同時也要定義百分比值參照的那個量。這個量可以是相同元素的另一個屬性的值,也可以是祖先元素的某個屬性的值,甚至是格式化上下文的一個度量(比如包含塊的寬度)。

具體來說:

寬度(width)、間距(maring/padding)支持百分比值,但默認的相對參考值是包含塊的寬度;

高度(height)百分比的大小是相對其父級元素高的大小;

邊框圓角半徑(border-radius)支持百分比值,但水平方向相對參考值是盒子的寬度,垂直方向相對參考值是盒子的高度;

文本大小(font-size)支持百分比值,但相對參考值是父元素的font-size的值;

盒陰影(box-shadow)和文本陰影(text-shadow)不支持百分比值;

首先,支持百分比單位的度量屬性有其各自的參照基準,其次並非所有度量屬性都支持百分比單位。所以我們需要另闢蹊徑。

rem 適配方案

在 vw 方案出來之前,最被大眾接受的就是使用 rem 進行適配的方案,因為 rem 滿足上面說的,可以是一個全局性的基準單位。

rem(font size of the root element),在 CSS Values and Units Module Level 3[5]中的定義就是, 根據網頁的根元素來設置字體大小,和 em(font size of the element)的區別是,em 是根據其父元素的字體大小來設置,而 rem 是根據網頁的跟元素(html)來設置字體大小。

flexible

基於此,淘寶早年推行的一套以 rem 為基準的適配方案:lib-flexible[6]。其核心做法在於:

根據設備的 dpr 動態改寫 <meta> 標籤,設置 viewport 的縮放給 <html> 元素添加 data-dpr 屬性,並且動態改寫 data-dpr 的值根據 document.documentElement.clientWidth 動態修改 <html> 的 font-size ,頁面其他元素使用 rem 作為長度單位進行布局,從而實現頁面的等比縮放

關於頭兩點,其實現在的 lib-flexible 庫已經不這樣做了,不再去縮放 Viewport,字體大小的設定也直接使用了 rem

hotcss

hotcss[7] 不是一個庫,也不是一個框架。它是一個移動端布局開發解決方案。使用 hotcss 可以讓移動端布局開發更容易。本質的思想與 flexible 完全一致。

對於 rem 方案的一些總結

使用 flexible/hotcss 作為屏幕寬度適配解決方案,是存在一些問題的:

動態修改 Viewport 存在一定的風險的,譬如通過 Viewport 改變了頁面的縮放之後,獲取到的 innerWidth/innerHeight 也會隨之發生變化,如果業務邏輯有獲取此類高寬進行其他計算的,可能會導致意想不到的錯誤;

到今天,其實存在很多在 flexible 基礎上演化而來的各種 rem 解決方案,有的不會對 Viewport 進行縮放處理,自行處理 1px 邊框問題。

flexible/hotcss 都並非純 CSS 方案,需要引入一定的 Javascript 代碼rem 的設計初衷並非是用於解決此類問題,用 rem 進行頁面的寬度適配多少有一種 hack 的感覺存在一定的兼容性問題,對於安卓 4.4 以下版本系統不支持 viewport 縮放(當然,flexible 處理 Android 系列時,始終認為其 dpr 為 1,沒有進行 viewport 縮放)vw 適配方案

嚴格來說,使用 rem 進行頁面適配其實是一種 hack 手段,rem 單位的初衷本身並不是用來進行移動端頁面寬度適配的。

到了今天,有了一種更好的替代方案,使用 vw 進行適配 。

百分比適配方案的核心需要一個全局通用的基準單位,rem 是不錯,但是需要藉助 Javascript 進行動態修改根元素的 font-size,而 vw/vh(vmax/vmin) 的出現則很好彌補 rem 需要 JS 輔助的缺點。

根據 CSS Values and Units Module Level 4:vw等於初始包含塊(html元素)寬度的1%,也就是

1vw 等於 window.innerWidth 的數值的 1%1vh 等於window.innerHeight 的數值的 1%

再以上面設計稿圖的元素為例,那麼,

元素的寬度為:209/375 = 55.73% = 55.73vw元素的高度為:80/375 = 21.33% = 21.33vw

根據相關的測試,可以使用 vw 進行長度單位的有:

簡單的一個頁面,看看效果,完全是等比例縮放的效果:

vw

CodePen Demo(移動端打開):使用 vw 進行頁面適配[8]

自動轉換插件

當我們使用 rem 作為長度單位的時,通常會有藉助 Sass/Less 實現一個轉換函數,像是這樣:

// 假設設計稿的寬度是 375px,假設取設計稿寬度下 1rem = 100px
$baseFontSize: 100;

@function px2rem($px) {
 @return $px / $baseFontSize * 1rem;
}

同理,在 vw 方案下,我們只需要去改寫這個方法:

// 假設設計稿的寬度是 375px

@function px2vw($px) {
 @return $px / 375 * 100vw;
}

當然,我們還可以藉助一些插件包去實現這個自動轉換,提高效率,譬如 postcss-px-to-viewport[9]

vw polyfill

vw 現在畢竟還是存在兼容問題的,看看兼容性:

image

其實已經覆蓋了絕大部分設備,那麼如果業務使用了且又真的出現了兼容問題,應該怎麼處理呢?有兩種方式可以進行降級處理:

CSS Houdini:通過CSS Houdini針對vw做處理,調用CSS Typed OM Level1 提供的 CSSUnitValue API。CSS Polyfill:通過相應的Polyfill做相應的處理,目前針對於 vw 單位的 Polyfill 主要有:vminpoly、Viewport Units Buggyfill、vunits.js和 Modernizr對於 vw 方案的一些總結

vw 確實看上去很不錯,但是也是存在它的一些問題:

也沒能很好的解決 1px 邊框在高清屏下的顯示問題,需要自行處理由於 vw 方案是完全的等比縮放,在完全等比還原設計稿的同時帶來的一個問題是無法很好的限定一個最大最小寬度值,由於 rem 方案是藉助 Javascript 的,所以這一點 rem 比 vw 會更加的靈活

當然,兩個方案現階段其實都可以使用甚至一起搭配使用,更多詳情可以讀讀:

Responsive And Fluid Typography With vh And vw Units[11]1px線

上面說到使用 vw 適配屏幕大小方案,其中有一個缺點就是在 Retina 屏下,無法很好的展示真正的 1px 物理像素線條。

設計師想要的 retina 下 border: 1px,其實是 1 物理像素寬度,而不是 1 CSS 像素寬度,對於 CSS 而言:

在 dpr = 1 時,此時 1 物理像素等於 1 CSS 像素寬度;在 dpr = 2 時,此時 1 物理像素等於 0.5 CSS 寬度像素,可以認為 border-width: 1px 這裡的 1px 其實是 1 CSS像素寬度,等於 2 像素物理寬度,設計師其實想要的是 border-width: 0.5px;在 dpr = 3 時,此時 1 物理像素等於 0.33 CSS 寬度像素,設計師其實想要的是 border-width: 0.333px

然而,並不是所有手機瀏覽器都能識別 border-width: 0.5px,在 iOS7 以下,Android 等其他系統裡,小於 1px 的單位會被當成為 0px 處理,那麼如何實現這 0.5px、0.33px 呢?

這裡介紹幾種方法:

使用SVG實現(嵌入 background url)

Retina 屏幕下 1px 線的實現[13]

圖片適配及優化

圖像通常佔據了網頁上下載資源的絕大部分。優化圖像通常可以最大限度地減少從網站下載的字節數以及提高網站性能。

通常可以,有一些通用的優化手段:

儘可能利用 CSS3\SVG 矢量圖像替代某些光柵圖像謹慎使用字體圖標,使用網頁字體取代在圖像中進行文本編碼

本文重點關注如何在不同的 dpr 屏幕下,讓圖片看起來都不失真。

首先就是上述的第二點,儘可能利用 CSS3\SVG 矢量圖像替代某些光柵圖像。某些簡單的幾何圖標,可以用 CSS3 快速實現的圖形,都應該儘量避免使用光柵圖像。這樣能夠保證它們在任何尺寸下都不會失真。

其次,實在到了必須使用光柵圖像的地步,也是有許多方式能保證圖像在各種場景下都不失真。

無腦多倍圖

在移動端假設我們需要一張 CSS 像素為 300 x 200 的圖像,考慮到現在已經有了 dpr = 3 的設備,那麼要保證圖片在 dpr = 3 的設備下也正常高清展示,我們最大可能需要一張 900 x 600 的原圖。

這樣,不管設備的 dpr 是否為 3,我們統一都使用 3 倍圖。這樣即使在 dpr = 1,dpr = 2 的設備上,也能非常好的展示圖片。

當然這樣並不可取,會造成大量帶寬的浪費。現代瀏覽器,提供了更好的方式,讓我們能夠根據設備 dpr 的不同,提供不同尺寸的圖片。

srcset 配合 1x 2x 像素密度描述符

簡單來說,srcset 可以根據不同的 dpr 拉取對應尺寸的圖片:

<div class='illustration'>
  <img src='illustration-small.png'
       srcset='images/illustration-small.png 1x,
               images/illustration-big.png 2x'
       style='max-width: 500px'/>
</div>

上面 srcset 裡的 1x,2x 表示 像素密度描述符,表示

當屏幕的 dpr = 1 時,使用 images/illustration-small.png 這張圖當屏幕的 dpr = 2 時,使用 images/illustration-big.png 這張圖srcset 屬性配合 sizes 屬性 w 寬度描述符

上面 1x,2x 的寫法比較容易接受易於理解。

除此之外,srcset屬性還有一個 w 寬度描述符,配合 sizes 屬性一起使用,可以覆蓋更多的面。

以下面這段代碼為例子:

<img 
        sizes = 「(min-width: 600px) 600px, 300px" 
        src = "photo.png" 
        srcset = 「photo@1x.png 300w,
                       photo@2x.png 600w,
                       photo@3x.png 1200w,
>

解析一下:

sizes = 「(min-width: 600px) 600px, 300px"的意思是,如果屏幕當前的 CSS 像素寬度大於或者等於 600px,則圖片的 CSS 寬度為 600px,反之,則圖片的 CSS 寬度為 300px。

也就是 sizes 屬性聲明了在不同寬度下圖片的 CSS 寬度表現。這裡可以理解為,大屏幕下圖片寬度為 600px,小屏幕下圖片寬度為 300px。(具體的媒體查詢代碼由 CSS 實現)

這裡的 sizes 屬性只是聲明了在不同寬度下圖片的 CSS 寬度表現,而具體使圖片在大於600px的屏幕上展示為600px寬度的代碼需要另外由 CSS 或者 JS 實現,有點繞。

srcset = 「photo@1x.png 300w, photo@2x.png 600w, photo@3x.png 1200w 裡面的 300w,600w,900w 叫寬度描述符。怎麼確定當前場景會選取哪張圖片呢?

當前屏幕 dpr = 2 ,CSS 寬度為 375px

當前屏幕 CSS 寬度為 375px,則圖片 CSS 寬度為 300px。分別用上述 3 個寬度描述符的數值除以 300。

上面計算得到的 1、 2、 4 即是算出的有效的像素密度,換算成和 x 描述符等價的值 。這裡 600w 算出的 2 即滿足 dpr = 2 的情況,選擇此張圖。

當前屏幕 dpr = 3 ,CSS 寬度為 414px

當前屏幕 CSS 寬度為 414px,則圖片 CSS 寬度仍為 300px。再計算一次:

因為 dpr = 3,2 已經不滿足了,則此時會選擇 1200w 這張圖。

當前屏幕 dpr = 1 ,CSS 寬度為 1920px

當前屏幕 CSS 寬度為 1920px,則圖片 CSS 寬度變為了 600px。再計算一次:

因為 dpr = 1,所以此時會選擇 600w 對應的圖片。

具體的可以試下這個 Demo:CodePen Demo -- srcset屬性配合w寬度描述符配合sizes屬性[14]

此方案的意義在於考慮到了響應性布局的複雜性與屏幕的多樣性,利用上述規則,可以一次適配 PC 端大屏幕和移動端高清屏,一箭多雕。

CSS 有個類似的屬性,image-set(),搭配使用,效果更佳。

了解更多細節,推薦看看:

Google Web Fundamentals -- Web Responsive Images[15]響應式圖片srcset全新釋義sizes屬性w描述符[16]字體適配方案字體大小

字體是很多前端開發同學容易忽略的一個點,但是其中也是有很多小知識點。

首先要知道,瀏覽器有最小字體限制:

如果小於最小字體,那麼字體默認就是最小字體。

其次,很多早期的文章規範都建議不要使用奇數級單位來定義字體大小(如 13px,15px...),容易在一些低端設備上造成字體模糊,出現鋸齒。

字體的選擇展示

在字體適配上面,我們需要從性能展示效果兩個維度去考慮。

完整的一個字體資源實在太大了,所以我們應該儘可能的使用用戶設備上已有的字體,而不是額外去下載字體資源,從而使加載時間明顯加快。

而從展示效果層面來說,使用系統字體能更好的與當前作業系統使用的相匹配,得到最佳的展示效果。所以我們在字體使用方面,有一個應該儘量去遵循的原則,也是現在大部分網站在字體適配上使用的策略:

使用各個支持平臺上的默認系統字體

兼顧各個作業系統

常見的作業系統有 Windows、Windows Phone、Mac OS X、iPhone、Android Phone、Linux。當然對於普通用戶而言,無須關注 Linux 系統。

下面就以 CSS-Trick[17] 網站最新的 font-family 為例,看看他們是如何在字體選擇上做到適配各個作業系統的

{
  font-family: 
    system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,
    Helvetica,Arial,
    sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;
}

font-family 關鍵字

對於 CSS 中的 font-family 而言,它有兩類取值。

一類是類似這樣的具體的字體族名定義:font-family: Arial 這裡定義了一個具體的字體樣式,字體族名為 Arial;

一類是通用字體族名,它是一種備選機制,用於在指定的字體不可用時給出較好的字體,類似這樣:font-family: sans-serif 。

其中,sans-serif 表無襯線字體族,例如, "Open Sans", "Arial" "微軟雅黑" 等等。

關於通用字體族名,在 CSS Fonts Module Level 3 -- Basic Font Properties[18] 中,定義了 5 個,也就是我們熟知的幾個通用字體族名:

monospace 等寬字體,即字體中每個字寬度相同新增通用字體族關鍵字

而在  CSS Fonts Module Level 4 -- Generic font families[19] 中,新增了幾個關鍵字:

fangsong 此字體系列用於中文的(仿宋)字體。

我們看看用的最多的 system-ui。

system-ui

簡單而言,font-family: system-ui 的目的就是在不同的作業系統的 Web 頁面下,自動選擇本作業系統下的默認系統字體。

默認使用特定作業系統的系統字體可以提高性能,因為瀏覽器或者 webview 不必去下載任何字體文件,而是使用已有的字體文件。font-family: system-ui 字體設置的優勢之處在於它與當前作業系統使用的字體相匹配,對於文本內容而言,它可以得到最恰當的展示。

San Francisco Fonts

OK,簡單了解了 system-ui 字體族。但是像 -apple-system、BlinkMacSystemFont 沒有在最新的標準裡出現。它們又代表什麼意思呢?

在此之前,先了解下 San Francisco Fonts 。

San Francisco Fonts 又叫舊金山字體,是一款西文字體。隨著 iOS 9 更新面世,在 WatchOS 中隨 Apple Watch 一起悄然發售,並且還將在 Apple TV 上的新 tvOS 中使用。

San Francisco Fonts 在 iOS 系統上用於替代升級另外一款西文字體 Helvetica Neue。Apple 做了一些重要的改變,使其成為平臺上更好的, 甚至是完美的西文字體。

image-apple-system/BlinkMacSystemFont

話說回來。正如每個前端開發人員都知道的那樣,將一個功能納入規範是一回事,將其納入瀏覽器又是另一回事。

幸運的是,system-ui 的普及很快。Chrome 和 Safari 都可以在各種平臺上完全支持它。只有 Mozilla 和 Windows 相對落後。

看看 system-ui 的兼容性,Can i Use -- system-ui[20](圖片截取日 2019-08-13):

image

仔細看上圖的最後兩行:

Supported as the -apple-system value (only on macOS and iOS)Supported as the BlinkMacSystemFont value (only on macOS)

考慮到不同平臺及向後兼容,在 macOS 和 iOS 上,我們需要使用 -apple-system 及 BlinkMacSystemFont 來兼容適配 system-ui 標準。

Segoe UI

Segoe UI 是 Windows 從 Vista 開始的默認西文字體族,只有西文,不支持漢字,屬於無襯線體。

它也表示一個系列而不是某一款單一字體。使用 font-family: Segoe UI 可以在 Windows 平臺及 Windows Phone 上選取最佳的西文字體展示。

Roboto

Roboto 是為 Android 作業系統設計的一個無襯線字體家族。Google 描述該字體為「現代的、但平易近人」和「有感情」的。

這個字體家族包含Thin、Light、Regular、Medium、Bold、Black六種粗細及相配的斜體。

總結一下

到此,我們可以總結一下了。以 CSS-Tricks[21] 網站的 font-family 定義為例子:

{
  font-family: 
    system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,
    Helvetica,Arial,
    sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;
}

system-ui,使用各個支持平臺上的默認系統字體-apple-system, 在一些稍低版本 Mac OS X 和 iOS 上,它針對舊版上的 Neue Helvetica 和 Lucida Grande 字體,升級使用更為合適的 San Francisco FontsBlinkMacSystemFont,針對一些 Mac OS X 上的 Chrome 瀏覽器,使用系統默認字體segoe ui,在 Windows 及 Windows Phone 上選取系統默認字體Roboto,面向 Android 和一些新版的的 Chrome OSHelvetica,Arial,在針對不同作業系統不同平臺設定採用默認系統字體後,針對一些低版本瀏覽器的降級方案sans-serif,兜底方案,保證字體風格統一,至少也得是無襯線字體

上述 5 個字體族定義,優先級由高到底,可以看到,它們 5 個都並非某個特定字體,基本的核心思想都是選擇對應平臺上的默認系統字體。

涵蓋了 iOS、MAC OS X、Android、Windows、Windows Phone 基本所有用戶經常使用的主流作業系統。

使用系統默認字體的主要原因是性能。字體通常是網站上加載的最大/最重的資源之一。如果我們可以使用用戶機器上已有的字體,我們就完全不需要再去獲取字體資源,從而使加載時間明顯加快。

並且系統字體的優點在於它與當前作業系統使用的相匹配,因此它的文本展示必然也是一個讓人舒適展示效果。

當然,上述 font-family 的定義不一定是最佳的。譬如天貓移動端在 font-family 最前面添加了 "PingFang SC",miui,..必定也有他們的業務上的考慮。但是一些 fallback 方案向後兼容的思想都是一致的,值得參考學習。

更多的關於字體方面的細節知識,可以看看這幾篇文章:

你該知道的字體 -- font-family[22]Web 字體 font-family 再探秘[23]Using UI System Fonts In Web Design: A Quick Practical Guide[24]Apple’s San Francisco Font[26]前端布局的兼容適配

前端工程師的一大工作內容就是頁面布局。無論在PC端還是移動端,頁面布局的兼容適配都是重中之重。在整個前端發展的歷程中,布局的方法也在不斷的推陳出新。

布局發展歷程

簡單來說,前端的布局發展歷程經歷了下面幾個過程:

表格布局 --> 定位布局 --> 浮動布局 --> flexbox布局 --> gridbox布局

每一種布局在特定時期都發揮了重要的作用,而每一種新的布局方式的出現,往往都是因為現有的布局方式已經在該時期已經無法很好的滿足開發者的需求,無法滿足越來越潮流的頁面布局的方式。

以 Flexbox 的出現為例子,在 Flexbox 被大家廣為接受使用之前。我們一直在使用定位+浮動的布局方式。像下面這個布局:

容器寬度不定,內部三個元素,均分排列且佔滿整個空間,並且垂直居中。如果使用定位+浮動的布局方式,你無法很快想到最佳的解決方式。三個元素並排那麼必然需要浮動或者絕對定位,容器寬度不定且中間元素始終居中,需要顧慮的方面就很多了。也許使用 text-align: justufy 可以 hack 實現,等等等等。

然而,使用 flexbox 布局的話,只需要:

.container {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

flexbox 的出現,一次性解決了流動布局,彈性布局,排列方式等多個問題。並且它是簡潔的,可控的。

再來看一個例子,水平垂直居中一個元素。使用 flexbox 也許是最便捷的:

.container {
    display: flex;
}

.item {
    margin: auto;
}

最便捷的垂直居中方式[27]

CSS Grid Layout

OK,flexbox 已經足夠優秀了,為什麼 gird 網格布局的出現又是為什麼?它解決了什麼 flex 布局無法很好解決的問題?

看看下面這張圖:

flexbox 是一維布局,他只能在一條直線上放置你的內容區塊;而grid是一個二維布局。它除了可以靈活的控制水平方向之外,還能輕易的控制垂直方向的布局模式。對於上圖那樣的九宮格布局,它就可以輕而易舉的完成。

一圖以蔽之,flexbox:

gridbox:

圖片截取自陳慧晶老師在 2019 第五屆 CSS 大會上的分享 -- 新時代CSS布局[28]

在現階段,移動端布局應當更多使用 flexbox 去完成(相對那些還在使用 float 布局的),而考慮到未來頁面布局的推陳出新。對於 Grid 布局我們應當像前幾年對待 flexbox 一樣,重視起來,隨著兼容性的普及,Grid 布局也會慢慢成為主流。

最後

好了,本文到此結束,希望對你有幫助 :)

更多精彩技術文章匯總在我的 Github -- iCSS[29] ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

參考資料[1]

什麼是響應式布局設計?: https://www.zhihu.com/question/20976405

[2]

Quora - Responsive Design vs. Adaptive Design?: https://www.quora.com/What-is-the-difference-between-responsive-and-adaptive-design

[3]

zhihu -- Responsive design 和 Adaptive design 的區別: https://www.zhihu.com/question/20628050?rf=24334181

[4]

CSS Values and Units Module Level 4: https://www.w3.org/TR/css-values-4/#percentages

[5]

CSS Values and Units Module Level 3: https://drafts.csswg.org/css-values-3/#lengths

[6]

lib-flexible: https://github.com/amfe/lib-flexible

[7]

hotcss: https://github.com/imochen/hotcss

[8]

CodePen Demo(移動端打開):使用 vw 進行頁面適配: https://codepen.io/Chokcoco/pen/oNvWVYq?editors=1100

[9]

postcss-px-to-viewport: https://www.npmjs.com/package/postcss-px-to-viewport

[10]

再聊移動端頁面的適配: https://juejin.im/entry/5a9d07ee6fb9a028c149f55b

[11]

Responsive And Fluid Typography With vh And vw Units: https://www.smashingmagazine.com/2016/05/fluid-typography/

[12]

使用VH和VW實現真正的流體排版: https://www.cnblogs.com/wengxuesong/archive/2016/05/16/5497653.html

[13]

Retina 屏幕下 1px 線的實現: https://codepen.io/Chokcoco/pen/XyNjqK

[14]

CodePen Demo -- srcset屬性配合w寬度描述符配合sizes屬性: https://codepen.io/Chokcoco/pen/WNeZvOX?editors=1100

[15]

Google Web Fundamentals -- Web Responsive Images: https://developers.google.com/web/fundamentals/design-and-ux/responsive/images

[16]

響應式圖片srcset全新釋義sizes屬性w描述符: https://www.zhangxinxu.com/wordpress/2014/10/responsive-images-srcset-size-w-descriptor/

[17]

CSS-Trick: https://css-tricks.com/

[18]

CSS Fonts Module Level 3 -- Basic Font Properties: https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#generic-font-families

[19]

CSS Fonts Module Level 4 -- Generic font families: https://www.w3.org/TR/css-fonts-4/#generic-font-families

[20]

Can i Use -- system-ui: https://caniuse.com/#search=system

[21]

CSS-Tricks: https://css-tricks.com/

[22]

你該知道的字體 -- font-family: https://github.com/chokcoco/iCSS/issues/6

[23]

Web 字體 font-family 再探秘: https://github.com/chokcoco/iCSS/issues/69

[24]

Using UI System Fonts In Web Design: A Quick Practical Guide: https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/

[25]

System Fonts in CSS: https://furbo.org/2018/03/28/system-fonts-in-css/

[26]

Apple’s San Francisco Font: https://designforhackers.com/blog/san-francisco-font/

[27]

最便捷的垂直居中方式: https://codepen.io/Chokcoco/pen/GarPev

[28]

新時代CSS布局: https://www.chenhuijing.com/slides/53-cssconfcn-2019/#/

[29]

Github -- iCSS: https://github.com/chokcoco/iCSS

相關焦點

  • 移動端 h5開發相關內容總結——CSS篇
    (點擊上方公眾號,可快速關注)作者:伯樂在線專欄作者 - zhiqiang21如有好文章投稿,請點擊 → 這裡了解詳情如需轉載,發送「轉載」二字查看說明1.移動端開發視窗口的添加h5端開發下面這段話是必須配置的meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">其它相關配置內容如下:width viewport 寬度(數值/device-width)height viewport
  • 移動端H5前端開發調試經驗總結
    除此之外,Chrome 的手機模擬器還提供了非常非常多的實用功能,比如模擬 touch 事件、捏等手勢操作、地理位置、加速計、Retina 等等,詳情請見 官方文檔,英文不好的朋友可以看我的 翻譯版本。節約篇幅,這裡不再贅述。這裡的方法僅能作為基礎的響應式測試,對於中小型、比較簡單的項目,完全足夠用了,對於稍微複雜的頁面,還是需要用虛擬機或者真機測試,這樣更加可靠。
  • 移動端開發H5調試方案
    一、概要因為移動端作業系統分為 iOS 和 Android 兩派,所以本文的調試技巧也會按照不同的系統來區分。尋找最合適高效的方式,才能讓你事半功倍。文章會列舉目前適合移動端調試的多種方案,快來選擇你的最佳實踐吧!
  • 移動端h5自適應適配之flexible.js打假
    最近做一個移動端的h5適配,在網上找方案基本上都是使用flexible.js,然後順理成章我也入了這個坑
  • 移動端尺寸基礎知識
    原文連結:http://www.ui.cn/detail/48317.html從原理開始介紹一下移動端設計尺寸規範。初涉移動端設計和開發的同學們,基本都會在尺寸問題上糾結好一陣子才能摸到頭緒。我也花了很長時間才弄明白,感覺有必要寫一篇足夠通俗易懂的教程來幫助大家。
  • H5基礎知識
    H5基礎知識0. HTML概念HTML:超文本標記語言(Hyper Text Markup Language)。是用來描述網頁的一種語言。HTML不是一種程式語言,而是一種標記語言(markup language)。標記語言是一套標記標籤(markup tag)。1.
  • vue移動端開發總結
    相對於PC端來說,移動端設備解析度百花齊放,千奇百怪,對於每一個開發者來說,移動端適配是我們進行移動端開發第一個需要面對的問題。所以現在我們知道,這段在移動端常見的代碼的意思,即將visualviewport和layoutviewport設置為idealviewport的值;這樣我們在移動端就不會出現滾動條,網頁內容可以比較好的展示出來,在這個前提下我們再考慮頁面的適配問題。
  • 魯班H5作者:@小小魯班
    自我介紹就叫小小魯班吧(真名可以不說嗎)一隻沒有去過大廠,一直在某創業公司的前端工程師,平時的工作以 ToB 端的平臺開發為主(沒錯,就是大家理解上的那些管理後臺 😂)在公司用的技術棧以 Vue.js 為主,React 也有涉獵。python可以寫一些簡單的demo。
  • 開發 h5| Hybrid | 微信小程序 | 實踐踩坑總結十六條
    這篇文章主要是針對 h5| Hybrid | 微信小程序 三個方向來講述我遇到的坑,以及詳細講解我是如何解決問題的。一直以來,移動端適配就是一個令人頭疼的問題。如果想要吃透移動端,還需要不少的實踐經驗,有的時候在pc端調試沒有問題,但是在m端就會出現問題。以下這16個問題是我在實際工作中遇到的,親自奉上給大家。希望大家收藏一波,以備不時之需。
  • H5移動端知識點總結(一)
    移動開發基本知識點一.
  • 微信H5頁面前端開發,大多數人都會遇到的幾個兼容性坑
    最近給公司微信公眾號,寫了微信h5業務頁面,總結分享一下前端開發過程中的幾個兼容性坑,項目直接拿的公司頁面,所以下文涉及圖片都模糊處理了。h5頁面上下滑動時卡頓、頁面缺失問題詳情描述:在ios端,上下滑動頁面時,如果頁面高度超出了一屏,就會出現明顯的卡頓,頁面有部分內容顯示不全的情況,例如下圖,右圖是正常頁面,邊是ios上下滑動後,卡頓導致如左圖下面部分丟失。
  • Vue.js開發移動端經驗總結
    移動端適配相對於PC端來說,移動端設備解析度百花齊放,千奇百怪,對於每一個開發者來說,移動端適配是我們進行移動端開發第一個需要面對的問題。user-scale=no禁止縮放所以現在我們知道,這段在移動端常見的代碼的意思,即將visualviewport和layoutviewport設置為idealviewport的值;這樣我們在移動端就不會出現滾動條,網頁內容可以比較好的展示出來,在這個前提下我們再考慮頁面的適配問題。
  • 收藏 | 移動端H5開發常用技巧總結
    html 篇常用的meta屬性設置meta對於移動端的一些特殊屬性,可根據需要自行設置<meta name="screen-orientation" content="portrait"> //Android 禁止屏幕旋轉<meta name="
  • 前端第1課 前端簡介及html基礎知識
    今日知識框架知識點1  什麼是前端?
  • H5 移動端調試全攻略
    ,H5 開發也成為了 F2E 不可或缺的能力。而移動開發的重中之重就是掌握調試技巧,修 Bug 於無形。一、概要因為移動端作業系統分為 iOS 和 Android 兩派,所以本文的調試技巧也會按照不同的系統來區分。尋找最合適高效的方式,才能讓你事半功倍。文章會列舉目前適合移動端調試的多種方案,快來選擇你的最佳實踐吧!
  • 網頁開發語言有哪些?移動端網頁開發用什麼?
    網頁開發語言有哪些?
  • 【Vuejs】845- Vuejs開發移動端經驗總結
    移動端適配相對於PC端來說,移動端設備解析度百花齊放,千奇百怪,對於每一個開發者來說,移動端適配是我們進行移動端開發第一個需要面對的問題。user-scale=no禁止縮放所以現在我們知道,這段在移動端常見的代碼的意思,即將visualviewport和layoutviewport設置為idealviewport的值;這樣我們在移動端就不會出現滾動條,網頁內容可以比較好的展示出來,在這個前提下我們再考慮頁面的適配問題。
  • 移動端 模擬手機聯繫人觸摸A~Z導航
    HTML5學堂:今天要與大家分享一個當前移動端很常見的效果,類似於手機聯繫人的快速導航功能,即當觸摸a~z的字母時,能夠相對應的顯示文字。
  • 移動端設備前端開發調試的方法技巧
    ,所以算是積累了一點移動端調試的經驗,在這裡分享一下。通過移動端使用Web服務的比率越來越大,掌握移動端的前端開發和測試是非常有必要的,但本文只介紹與調試有關的內容,至於其他移動端開發知識太多太大,我們在此就不一一的介紹了。一、響應式測試響應式現在基本是中小型項目的標配了,先來談談響應式測試技巧。
  • 【第134期】移動端前端開發調試
    【早讀君聊聊】這篇是早讀君節前某天凌晨4點半在微博上看到的,非常詳細的一篇介紹移動端調試的文章,不可過錯~~ 本文只介紹與調試有關的內容,至於其他移動端開發知識(技巧、坑)太多太大,推薦 Mars 移動前端開發知識庫。