title: 移動端Web頁面適配淺析
date: 2018-01-31 16:38:01
tags: 移動端 適配
移動端Web頁面適配淺析
以前對移動端Web適配的原理一頭霧水,對于幾個概念dpr
、ppi
、viewport
、device-width
等的概念用法邏輯總是有些迷茫。最近重新閱讀了幾篇好文章,也自己去查了一些相關的概念,對這一塊再重新加深了理解。文章力求直觀描述移動端Web頁面的適配思路,以及適配過程中有必要了解的基礎概念。部分用詞、概念及公式使用可能不妥,望指正。
移動端適配的經驗總結參考文章
從網易與淘寶的font-size思考前端設計稿與工作流-流云諸葛
Native 適配過程
要了解移動Web端的適配思路,首先要知道終端都是如何進行適配的。
無論是iOS還是Android端,設計通常給的設計稿標注是dp
或者pt
。
為了明確dp
以及pt
的概念,在這里對文章進行了一些總結,如果需要更為具體的內容,請參考如下文章:徹底理解 UI 及 Web 的尺寸單位:基本觀念-Taylor Hu
pt
、dp
是屏幕密度無關的單位
pt
(point)是iOS開發的單位,dp
(density-independent pixels )是google開發的單位。兩者都是屏幕密度無關的單位,也就是和屏幕一個平方單位內實際的物理像素的個數(即屏幕密度)無關。
再形象一點,以iOS為例,假設用標準的尺子畫一個1cm1cm的矩形框,那么無論是iPhone顯示屏清晰度不同的第一代低清顯示屏,還是iPhoneX的超視網膜高清屏,框出來的屏幕面積都是1cm^2。 iOS設計pt
單位就是這么一個思路,你可以把pt
想象成毫米,微米等絕對長度單位,是一個與設備物理像素無關的單位。這樣一來,如果我們假設1pt
= 1cm 且iPhone6設計稿中一個按鈕的寬度是10pt
,那么就意味著在任何屏幕密度的iPhone屏幕上,這個按鈕都為10cm*寬。
實際蘋果公司在定義pt
單位的時候,就是以第一代屏幕(iPhone3GS)為基準,第一代屏幕(iPhone3GS)的一個物理的像素點寬度為1pt
,設備像素比dpr
(devicePixelRatio)為1。隨著iPhone 屏幕的升級,1pt1pt* 內的物理像素點就會增多,屏幕密度也逐漸變高,到了iPhone4 ,1pt1pt* 內就包含了4個物理像素點,dpr
就為2,到了iPhone6 plus,1pt1pt* 內理論上有9個物理像素點,dpr
為3(為什么是理論上有9個物理像素點,之后再分析)。從這里就可以推導出設備像素比dpr
的一個直觀的概念,即$1pt = 設備像素比(dpr)*物理像素點寬$ 。
回到上面的例子,這個例子產生一個問題:假設1pt
= 1cm ,iPhone6設計稿上一個按鈕的寬度是10pt
,那么無論在什么屏幕上,這個按鈕都為10cm寬。這個寬度的按鈕放到iPhone6以下的手機,例如iPhone5s,iPhone4等看起來不就會過寬么?沒錯,就是會過寬!所以實際iOS工程師在適配的過程中,會根據不同iPhone物理分辨率進行換算后的邏輯分辨率進行等比例的縮放。根據表格中的邏輯分辨率,iPhone6設計稿上一個按鈕的寬度是10pt
,那么如果需要適配iPhone5s,就需要根據iPhone5s邏輯分辨率寬度320及iPhone6邏輯分辨率寬度375將按鈕進行等比例的縮放。
$iPhone5s 按鈕的寬度 = iPhone6 按鈕的寬度10pt*(iPhone5s邏輯分辨率寬度320/iPhone6邏輯分辨率寬度375)$
iOS適配過程
下圖是到目前為止,所有iPhone手機屏幕的尺寸、物理分辨率以及邏輯分辨率等詳細參數的匯總:
設備 | 屏幕尺寸 | 分辨率(pt) | Reader | 分辨率(px) | ppi |
---|---|---|---|---|---|
iPhone 3GS | 3.5吋 | 320x480 | @1x | 320x480 | 163 |
iPhone 4/4s | 3.5吋 | 320x480 | @2x | 640x960 | 330 |
iPhone 5/5s/5c | 4.0吋 | 320x568 | @2x | 640x1136 | 326 |
iPhone 6 | 4.7吋 | 375x667 | @2x | 750x1334 | 326 |
iPhone 6Plus | 5.5吋 | 414x736 | @3x | 1080x1920 | 401 |
iPhone 6s | 4.7吋 | 375x667 | @2x | 750x1334 | 326 |
iPhone 6sPlus | 5.5吋 | 414x736 | @3x | 1080x1920 | 401 |
iPhone 7 | 4.7吋 | 375x667 | @2x | 750x1334 | 326 |
iPhone 7Plus | 5.5吋 | 414x736 | @3x | 1080x1920 | 401 |
iPhone 8 | 4.7吋 | 375x667 | @2x | 750x1334 | 326 |
iPhone 8Plus | 5.5吋 | 414x736 | @3x | 1080x1920 | 401 |
iPhone X | 5.8吋 | 375x812 | @3x | 1125 x 2436 | 458 |
我們會發現@1x屏幕到@2x 屏幕是完全滿足1pt1pt* 范圍內從包含1個物理像素點到包含了4個物理像素點的轉換的,例如iPhone3GS到iPhone4、iPhone6、iPhone7、iPhone8;然而,iPhone6Plus、iPhone6sPlus、iPhone7Plus及iPhone8Plus似乎并不滿足1pt1pt* 范圍內從包含1個物理像素點到包含了9個物理像素點的轉換。
參考godlaugh的回答 ,在這里將原理進行簡單描述,我們以iPhone6Plus為例子進行深度的分析。
設備 | 屏幕尺寸 | 分辨率(pt) | Reader | 分辨率(px) | ppi | dpi |
---|---|---|---|---|---|---|
iPhone 6 | 4.7吋 | 375x667 | @2x | 750x1334 | 326 | 163 |
iPhone 6Plus | 5.5吋 | 414x736 | @3x | 1080x1920 | 401 | 154 |
iPhone 6Plus(a) | 5.5吋 | 414x736 | @3x | 1242x2208 | 461 | 154 |
iPhone 6Plus(b) | 5.5吋 | 360x640 | @3x | 1080x1920 | 401 | 134 |
iPhone 6Plus(c) | 5.5吋 | 540x960 | @2x | 1080x1920 | 401 | 200 |
iPhone 6Plus(d) | 6.7吋 | 540x960 | @2x | 1080x1920 | 326 | 163 |
iOS設計pt
單位是從兩個角度進行考慮:
- 整個屏幕可現實的內容多少
- 界面UI元素可點擊的物理區域大小
先理清ppi
,dpi
定義的區別
ppi : pixels per inch;
dpi : dots per inch,dot是指一個邏輯point。
再詳細分析:
-
iPhone 6Plus(b)方案:
保持iphone 6Plus 現有物理分辨率1080 * 1920 不變,
dpr
為3。此時邏輯分辨率將縮小到360 * 640,邏輯分辨率的長寬都比iphone6 的邏輯分辨率小。優點: iphone 6Plus(b)的屏幕密度更大,更為精細
缺點:實際可顯示的內容卻少于iphone6。
舉例:iphone6 一行顯示25個字符,iphone 6Plus(b) 僅能顯示24個字符。
?
-
iPhone 6Plus(c)方案:
保持iphone 6Plus 現有物理分辨率1080 * 1920 不變,
dpr
為2。此時邏輯分辨率將擴大到540 * 960 。在這種情況下,似乎應該選用iPhone 6Plus(d)方案,但是如果選用 iPhone 6Plus(d),在保持長寬比為16 : 9的比例下,iPhone 6Plus(d)屏幕將達不可思議的6.7吋,因此,該方案不可行。實際蘋果公司是根據市場需求,先確定plus手機的屏幕尺寸5.5吋,長寬比為16 : 9;再這個前提下,使用iPhone 6Plus(c)的方案(@2x)無可避免地需要相對iphone6 縮小每一個物理像素的大小。
優點: iphone 6Plus(c)的屏幕密度更大,實際可顯示的內容多于iphone6。
缺點:所有UI元素的尺寸在屏幕上的實際物理面積一下就變小了。
舉例:比如標簽欄或導航欄按鈕的物理高度只有原來的 81.5% (163/200),點擊面積就只有iPhone 6的 0.815*0.815=66.4%。
-
iPhone 6Plus(a) 方案:
該方案物理像素做到1242x2208,那么在5.5吋屏幕下
ppi
將達到461。優點: iphone 6Plus(a)的屏幕密度更大,實際可顯示的內容多于iphone6。
缺點:1)內存消耗巨大;
? 2)電池消耗巨大;
? 3)要做到 461ppi ,當前工藝可能存在一定難度
舉例: iphoneX 就在真正意義上做到@3x的顯示屏。
?
-
iPhone 6Plus 方案:
蘋果公司最終過渡選擇了iphone 6Plus方案估計是因為在5.5吋屏幕大小要求以及
ppi
小于461的前提下,只能選用該方案。也就是說,理論意義上 iphone 6Plus 并不是一個@3x屏幕,而是一個@2.46x(401/326*2) 左右的屏幕。這個倍數對于切圖造成了極大的困難,所以蘋果為方便開發者用的是@3x的素材,然后再縮放到@2.46x上,實際上是縮放到2.46/3=83%。
?
Android適配過程
和iOS 一樣,Google 也制定了一套密度等級規范屏幕參數,其中xxxhdpi
屏幕就是我們所說的4K。
密度類型 | 代表的分辨率(px) | dpi | Reader |
---|---|---|---|
中密度(mdpi) | 320x480 | 160 | @1x |
高密度(hdpi) | 480x800 | 240 | @1.5x |
超高密度(xhdpi) | 720x1280 | 320 | @2x |
超超高密度(xxhdpi) | 1080x1920 | 480 | @3x |
超超高密度(xxxhdpi) | 2160×3840 | 640 | @4x |
根據iOS設計pt
的思路,Google將mdpi的熒幕設置為基準點, mdpi熒幕上一個物理像素點的寬即為1dp
。對于dp
的理解以及屏幕尺寸參數之間的換算完全可以參考上一節原理。
這里需要說明:iOS工程師在布局過程中經常會使用絕對布局,因為iphone的型號和屏幕數量都極為有限。但是Android工程師在適配的過程中,由于屏幕的種類實在太多,就不能使用絕對布局了,而是改用其他布局方式,例如相對布局等。
舉例來說,設計師給xhdpi屏幕設計稿一個按鈕10dp寬,居中;那么Android工程師僅僅只需要關注這個10dp寬的按鈕,距離屏幕邊界的寬度,通過這樣的方式去適配所有的屏幕。
移動端Web適配過程
上一章節我們詳述了客戶端屏幕參數的含義及設計的思路,在這一節,我們需要詳述移動端的適配過程。
很多文章對視口(viewport)這個概念的闡述都僅限于定義,幸而發現一篇好文章:
文章本身直觀的解釋了各個視口的定義及其關系。本文基于該文章進行了總結,并添加演示代碼,力求更簡潔明了的表述視口(viewport)的概念及關系。
像素
和native適配一樣,iOS有pt
單位,Android使用dp
單位,對于前端開發人員來說,CSS pixel 的含義和pt
以及dp
是一樣的,具體定義可參考<length>。
也就是說,在普通屏幕上,開發PC端網頁設定固定寬度為1000px,在retina屏幕的macbook pro上網頁的寬度也是1000px。
對于retina 化前端網頁,可參考http://mir.aculo.us/2012/06/26/flowchart-how-to-retinafy-your-website/
視口
在討論移動端適配的過程中,我們要明確視口的定義及其之間的關系:布局視口與可視視口。
以PC端瀏覽網頁為例。
在瀏覽過程中會產生兩個視口:可視視口(visual viewport)及布局視口(layout viewport)。
在100%顯示比例下,
可視視口(visual viewport)通俗地說,就是用戶瀏覽網頁時瀏覽器框出來的區域。
布局視口(layout viewport)通俗地說,就是用戶瀏覽的網頁寬高包含的區域。
黑線框出的區域就是可視視口(visual viewport),而網頁本身明顯更長于可視視口(visual viewport),所以網頁所在的寬高包含的區域就是布局視口(layout viewport)。
那這兩個視口之間有什么關系呢,我們嘗試做一個試驗。
首先確定縮放比例為100%,可以看見google搜索的按鈕高度為36px
。
當縮放比例擴大到200%時,可以看見同一個搜索的按鈕高度仍舊為36px
。
通過兩張圖直觀的對比總結三點:
- 縮放比例的改變給用戶直觀的放大縮小的效果;
-
input
元素樣式上高度并不會隨著縮放比例的變化而變化;
3.** 縮放比例改變了CSS 像素與設備物理像素之間的比例關系**;
通過我們對可視視口(visual viewport)以及布局視口(layout viewport)的直觀理解,我們可以得出的一點就是,縮放比例不會改變布局視口的寬度,那么縮放比例到底是不是通過改變可視視口(visual viewport)來實現放大和縮小的效果的呢?答案是肯定的。
可視視口(visual viewport)的寬度可以通過如下代碼獲得
window.innerWidth
首先,最大化情況下,縮放比例為100%,可視視口寬度為1920px
。
其次,最大化情況下,縮放比例為200%,可視視口寬度為960px
。
然后,最大化情況下,縮放比例為50%,可視視口寬度為3840px
。
最后,非最大化情況下,縮放比例為100%,可視視口寬度為942px
。
通過這組對比,我們可以得出可視視口的兩個非常重要的特點。
? **1. 可視視口收到縮放比例的影響 **
? 瀏覽器窗口相同的情況下,縮放比例越大,可視視口寬度越小;縮放比例越小,可視視口寬度越大。
? 2. 可視視口與瀏覽器窗口的大小有關
? 縮放比例相同的情況下,瀏覽器窗口越大,可視視口寬度越大;瀏覽器窗口越小,可視視口寬度越小。
移動端訪問網頁時的視口
移動端訪問頁面的情況會相對復雜一些,我們來進行逐步的分解。
如果我們不做任何meta
設置,使用移動端訪問一個正常的頁面,將會出現頁面被縮小,以至于文字無法閱讀。這種狀態,就好像拿著一個手機屏幕大小的框,然后為了能夠將一個桌面端寬度的網頁全部放到框里,于是框到網頁距離被擴大,導致了頁面縮小的情況。另外,可以發現原始狀態iphone6訪問頁面,html文檔的寬度是980px,ipad pro 訪問頁面,html文檔的寬度是1024px。
通過<meta name="viewport" content="width=400">
將布局寬度設置成400px以后,我們看到頁面被放大了,文字也能看的清楚了。
通過上述實驗說明了移動端訪問網頁的時候,布局視口(layout viewport)實際存在。且有以下幾個特點:
- 衡量單位: CSS px。
- 默認值: 寬度有默認值,由手機瀏覽器定義。一般是768px ~ 1024px之間,常見默認值為980px。
-
移動端設置:可以通過
meta
的viewport
標簽中width
設定;例如<meta name="viewport" content="width=400">
- 縮放,滑動頁面,翻轉手機屏幕等均不影響布局視口。
- 使用媒體查詢時 max-width 和 min-width 的值指的也是布局視口的寬。
獲取布局視口寬度的js
document.documentElement.clientWidth
將上文可視視口(visual viewport)進行總結。有以下幾個特點:
衡量單位: CSS px。
默認值 : 無。
-
受到屏幕寬度以及縮放大小的影響。
用戶手動縮放和在
meta
標簽中設置initial-scale
的值都會改變可視視口的尺寸; 縮放比例也有默認的值,沒有設置 initial-scale 時,瀏覽器會取適當的縮放比例使布局視口正好鋪滿屏幕即有 布局視口尺寸 = 可視視口尺寸 。縮放比例是根據下面提到的理想視口而言的 ,$縮放比例 = 理想視口尺寸 / 可視視口尺寸$
獲取可視視口寬度的js
window.innerWidth
通過對native適配過程的論述,我們已經知道無論是iOS系統手機還是Android系統手機,都會存在一個邏輯分辨率,而邏輯分辨率組成的視口就是理想視口(ideal viewport),有以下幾個特點:
device-width
指的就是理想視口的寬度,例如<meta name="viewport" content="width=device-width">
-
理想視口尺寸不能設定也不能改變,它只與設備物理像素、dpr、以及瀏覽器相關。
$設備像素比(dpr) = 物理像素數 / 理想視口尺寸$
獲取理想視口寬度的js
screen.width
獲取設備dpr的js
window.devicePixelRatio
那么上述三種視口之間的轉換就有一定的規律:
-
將 meta 標簽中的 width 設為 device-width 同時禁用手動縮放
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
可以使$ 布局視口尺寸 = 可視視口尺寸 = 理想視口尺寸$,此時 設備像素比 = 物理像素數 / 理想視口尺寸 = 物理像素數 / 布局視口尺寸,對iphone5,一個CSS像素對應4個物理像素。
為 initial-scale 設置任意合法的值同時禁用手動縮放就可以使布局視口尺寸 = 可視視口尺寸
將 initial-scale 設置為 1 也可以使 布局視口尺寸 = 可視視口尺寸 = 理想視口尺寸
移動端Web適配方案
無論網易的移動Web適配方案,還是手淘的移動Web適配方案均采用rem
作為布局的單位。
rem(font size of the root element),指相對于根元素的字體大小的單位。
rem單位出現前的移動Web適配方案
在rem
單位出現以前,假設需求是適配iPhone4(320px),iPhone6(375px),iPhone6 Plus(414px),且用戶瀏覽網頁的時候,文字大小、圖片、按鈕大小都是適宜的:
(1) iPhone4的時候,希望網頁的內容文字大小12px=12*(320/320)px,按鈕的大小是240px。
(2)iphone6的時候,希望網頁的內容文字大小14px=12*(375/320)px,按鈕的大小是280px,等比縮放。
(3)iphone6 Plus的時候,希望網頁的內容文字大小15.5px=12*(414/320)px,按鈕的大小是310px,等比縮 放。
那么將采用以下的方案適配:
iphone 4 下
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0 />
iPhone6 調整縮放比例, initial-scale=375/320 =1.18
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.18 />
iphone 6Plus 再調整縮放比例,initial-scale=414/320 =1.30
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.30 />
隨著initial-scale的變大,網頁被拉伸的越來越厲害,那么,大屏的移動端顯示圖片、文字等會出現不同程度的模糊。
網易移動Web適配方案
-
設置理想視口=可視視口=布局視口
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
-
如何計算得出html的font-size
iphone6 的設計稿寬度為750px,100是期望換算比。即設計稿100px對應css 1rem;
$設計稿可視視口寬度=750px/100$,所以$1rem =可視視口寬度/(100/750) $;
可視視口寬度可以通過js 獲取:
window.innerWidth
html的font-size
document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
手淘移動Web適配方案
手淘flexible方案只對iOS設備進行dpr的判斷,對于Android系列,都始終認為dpr為1。
-
取 dpr 的倒數作為縮放比例,對 iOS 設備 dpr = window.devicePixelRatio ,其他設備認為 dpr 為 1
對 iOS 設備,令上面提到的公式 縮放比例 = 理想視口尺寸 / 可視視口尺寸,設備像素比 = 物理像素數 / 理想視口尺寸 中 設備縮放比 = 1 / 縮放比例 可以推出 可視視口尺寸 = 物理像素數,同時由于沒有設置 meta 標簽的 width 值,有 布局視口尺寸 = 可視視口尺寸 = 物理像素數,這意味著布局視口中的像素單位是和物理像素一一對應的,css單位中1px嚴格等于一個物理像素。對非 iOS 設備,將 dpr 設為 1,縮放比例也為 1,和網易新聞的方案相同。
對于描述性文本,則根據data-dpr進行區分,使用px作為單位。
另外手淘方案已經進行了更新,請戳這里