詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】


詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

作者:ChokCoco

https://www.cnblogs.com/coco1s/p/11463599.html

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

不知道小夥們是否還得小編之前也整理了2篇關於移動端各種機型適配問題詳細解答,咱們一起來回顧回顧(有興趣的小夥伴建議看看):

大廠是怎麼做移動端適配的

手把手教你繞過移動端適配大坑


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

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

什麼是響應式設計

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

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

這裡百度或者谷歌一下會有各種各樣的答案。這裡一段摘自知乎上我覺得很棒的一個答案:什麼是響應式佈局設計?(地址:https://www.zhihu.com/question/20976405)

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

為什麼要設計響應式界面

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

  • 即便是PC或Mac用戶,有查顯示只有一半的人會將瀏覽器全屏顯示,而剩下的一般人使用多大的瀏覽器,很難預知;
  • 臺式機、投影、電視、筆記本、手機、平板、手錶、VR……智能設備正在不斷增加,“主流設備”的概念正在消失;
  • 屏幕分辨率正飛速發展,同一張圖片在不同設備上看起來,大小可能天差地別;
  • 鼠標、觸屏、筆、攝像頭手勢……不可預期的操控方式正在不斷出現。

響應式界面的四個層次

  • 同一頁面在不同大小和比例上看起來都應該是舒適的;
  • 同一頁面在不同分辨率上看起來都應該是合理;
  • 同一頁面在不同操作方式(如鼠標和觸屏)下,體驗應該是統一的;
  • 同一頁面在不同類型的設備(手機、平板、電腦)上,交互方式應該是符合習慣的。

響應式界面的基本規則

  • 可伸縮的內容區塊:內容區塊的在一定程度上能夠自動調整,以確保填滿整個頁
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

  • 可自由排布的內容區塊:當頁面尺寸變動較大時,能夠減少/增加排布的列
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

  • 適應頁面尺寸的邊距:到頁面尺寸發生更大變化時,區塊的邊距也應該變化
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

  • 能夠適應比例變化的圖片:對於常見的寬度調整,圖片在隱去兩側部分時,依舊保持美觀可用
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

  • 能夠自動隱藏/部分顯示的內容:如在電腦上顯示的的大段描述文本,在手機上就只能少量顯示或全部隱藏
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

  • 能自動摺疊的導航和菜單:展開還是收起,應該根據頁面尺寸來判斷
詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

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

  • 媒體查詢,邊界斷點的規則設定(Media queries && break point)
  • 內容的可伸縮性效果(Flexibel visuals)
  • 流式網格佈局(Fluid grids)
  • 主要內容呈現及圖片的高質量(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 可以在服務器端就進行優化,把優化過的內容送到終端上。

一圖勝千言。

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

漸進增強 vs. 優雅降級

  • 漸進增強(progressive enhancement):針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
  • 優雅降級(graceful degradation):一開始就構建完整的功能,然後再針對低版本瀏覽器進行兼容。

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

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

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

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

移動端屏幕適配方案

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

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

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

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

設備獨立像素

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

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

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

物理像素

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

可以看到,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 的屏幕稱為視網膜屏幕。

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

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

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

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

適配不同屏幕大小

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

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

  • 元素的寬度為:209/375 = 55.73%
  • 元素的高度為:80/375 = 21.33%
  • 元素的上左右邊距依次計算...

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

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

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

具體來說:

  • 寬度(width)、間距(maring/padding)支持百分比值,但默認的相對參考值是包含塊的寬度;
  • 高度(height)百分比的大小是相對其父級元素高的大小;
  • 邊框(border)不支持百分值;
  • 邊框圓角半徑(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中的定義就是, 根據網頁的根元素來設置字體大小,和 em(font size of the element)的區別是,em 是根據其父元素的字體大小來設置,而 rem 是根據網頁的跟元素(html)來設置字體大小。

flexible

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

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

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

hotcss

hotcss 不是一個庫,也不是一個框架。它是一個移動端佈局開發解決方案。使用 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
  • 文本大小的適配,可以使用 vw
  • 大於 1px 的邊框、圓角、陰影都可以使用 vw
  • 內距和外距,可以使用 vw

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

自動轉換插件

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

<code>// 假設設計稿的寬度是 375px,假設取設計稿寬度下 1rem = 100px$baseFontSize: 100;@function px2rem($px) {    @return $px / $baseFontSize * 1rem;}/<code>

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

<code>// 假設設計稿的寬度是 375px@function px2rem($px) {    @return $px / 375 * 100vw;}/<code>

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

vw polyfill

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

  • 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 會更加的靈活

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

  • 再聊移動端頁面的適配
  • H5必知必會之像素級還原設計稿
  • Responsive And Fluid Typography With vh And vw Units
  • 使用VH和VW實現真正的流體排版

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: 0.333px

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

這裡介紹幾種方法:

  • 漸變實現
  • 使用縮放實現
  • 使用圖片實現(base64)
  • 使用SVG實現(嵌入 background url)

Retina 屏幕下 1px 線的實現。

圖片適配及優化

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

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

  • 消除多餘的圖像資源
  • 儘可能利用 CSS3\SVG 矢量圖像替代某些光柵圖像
  • 謹慎使用字體圖標,使用網頁字體取代在圖像中進行文本編碼
  • 選擇正確的圖片格式
  • 為不同 DPR 屏幕提供最適合的圖片尺寸

本文重點關注如何在不同的 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 拉取對應尺寸的圖片:

<code>/<code>

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

  • 當屏幕的 dpr = 1 時,使用 images///p2.ttnews.xyz/60110c71d7df042770651365.jpg 這張圖
  • 當屏幕的 dpr = 2 時,使用 images/illustration-big.png 這張圖

srcset 屬性配合 sizes 屬性 w 寬度描述符

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

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

以下面這段代碼為例子:

<code>/<code>

解析一下:

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

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

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

srcset = “[email protected] 300w, [email protected] 600w, [email protected] 1200w 裡面的 300w,600w,900w 叫寬度描述符。怎麼確定當前場景會選取哪張圖片呢?

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

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

  • 300 / 300 = 1
  • 600 / 300 = 2
  • 1200 / 300 = 4

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

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

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

  • 300 / 300 = 1
  • 600 / 300 = 2
  • 1200 / 300 = 4

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

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

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

  • 300 / 600 = .5
  • 600 / 600 = 1
  • 1200 / 600 = 2

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

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

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

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

  • Google Web Fundamentals -- Web Responsive Images
  • 響應式圖片srcset全新釋義sizes屬性w描述符

字體適配方案

字體大小

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

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

  • PC上最小 font-size=12px
  • 手機上最小 font-size=8px

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

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

字體的選擇展示

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

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

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

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

兼顧各個操作系統

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

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

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

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 中,定義了 5 個,也就是我們熟知的幾個通用字體族名:

  • serif 襯線字體族
  • sans-serif 非襯線字體族
  • monospace 等寬字體,即字體中每個字寬度相同
  • cursive 草書字體
  • fantasy 主要是那些具有特殊藝術效果的字體

新增通用字體族關鍵字

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

  • system-ui 系統默認字體
  • emoji 用於兼容 emoji 表情符號字符
  • math 適用於數學表達式
  • 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 做了一些重要的改變,使其成為平臺上更好的, 甚至是完美的西文字體。

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

-apple-system/BlinkMacSystemFont

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

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

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

仔細看上圖的最後兩行:

  • 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 網站的 font-family 定義為例子:


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

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

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

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

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

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

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

  • 你該知道的字體 -- font-family
  • Web 字體 font-family 再探秘
  • Using UI System Fonts In Web Design: A Quick Practical Guide
  • System Fonts in CSS
  • Apple’s San Francisco Font

前端佈局的兼容適配

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

佈局發展歷程

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

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

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

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

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

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

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

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

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

<code>.container {display: flex;}.item {margin: auto;}/<code>

最便捷的垂直居中方式。

CSS Grid Layout

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

看看下面這張圖:

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】


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

一圖以蔽之,flexbox:

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

gridbox:

詳細講解移動端開發的屏幕、圖像、字體與佈局的兼容適配【圖文】

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

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

最後

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

推薦移動端適配問題詳解相關文章

大廠是怎麼做移動端適配的

手把手教你繞過移動端適配大坑

作者:ChokCoco

https://www.cnblogs.com/coco1s/p/11463599.html


分享到:


相關文章: