牆裂科普:移動端適配的基礎概念

雲棲直播~發表於2018-07-09

近幾年移動端裝置數量增長迅速,導致各種裝置螢幕尺寸不一,解析度也是不盡相同。 作為一個前端開發者,就不得不面對移動端頁面適配的問題,而適配的終極目標,就是讓頁面能在不同尺寸,不同解析度的移動裝置上,儘可能的實現合理(我對“合理”的認識是:在保證良好的使用者瀏覽體驗的前提下,儘可能的保留頁面的完整性)展示

常見的移動端適配方案主要有下面幾種:

  • 固定高度,寬度自適應
  • 固定寬度,viewport 縮放
  • 寬度 rem,viewport 縮放
  • vw 方案

不論適配的方案如何多變,但都繞不開幾個基礎概念,只有搞清楚了基礎概念,才能正確的理解適配方案的工作原理,更好的幫助我們解決實際開發中的問題。

畫素

pixel

在編寫桌面端 CSS 程式碼時我們經常會使用 px 單位,比如說 width: 200px;,設定一個元素為 200 畫素寬,如果該 CSS 程式碼應用到移動端裝置,它會產生不一樣的效果(看起來元素變小了),這是因為存在兩種畫素。

裝置畫素(device pixel,dp)

裝置畫素(又稱物理畫素),即螢幕的物理畫素,隨著裝置生產出來就固定不變了,單位是 pt。比如說 iPhone X 的解析度是 2436pt × 1125pt,表示螢幕由 2436 行,1125 列畫素點組成。

CSS 畫素(css pixel,px)

CSS 畫素(又稱虛擬畫素、裝置獨立畫素、邏輯畫素) 是 web 程式設計的概念,指的是 CSS 樣式程式碼中使用的邏輯畫素。px 是一個相對的單位(相對於裝置畫素),是影像顯示的基本單元,它既不是一個確定的物理量,也不是一個點或者小方塊,而是一個抽象概念。

作為一個抽象概念,CSS 畫素又具有兩個方面的相對性,即:

  • 在同一個裝置上,一個 CSS 畫素所代表的裝置畫素是可以變化的(縮放影響);
  • 在不同的裝置之間,一個 CSS 畫素所代表的裝置畫素是可以變化的(高密度影響);

畫素密度(Pixels Per Inch,PPI)

畫素密度,準確的說是每平方英寸(1 英寸等於 2.54 釐米)的面積上排列的畫素點數量。畫素密度越高,代表螢幕顯示效果越精細。

PPI

PPI 有對應的計算公式:

ppi formula

通過下圖更直觀的瞭解計算過程:

ppi iphone

裝置畫素比(Device Pixels Ratio,DPR)

裝置畫素比指在 未縮放 情況下,裝置畫素 與 CSS 畫素的初始比例關係。簡單理解就是在移動開發中 1 個 CSS 畫素佔用多少裝置畫素:

DPR

DPR 的計算方式如下:

dpr formula

簡單理解,DPR 與 PPI 呈正相關的關係,PPI 越大,則畫素點排列越緊密,DPR 也就越大。

PS:JavaScript 中可以通過 window.devicePixelRatio 程式碼得到 DPR 的值。

解析度

解析度指的是整塊螢幕的尺寸,與畫素密度(PPI)是不同的概念,不要混淆。

脫離螢幕尺寸單說單個裝置畫素大小沒有實際意義,因為你可以將 1920 * 1080 顆畫素放到一臺 40 寸的小米電視機裡面,也可以將同樣多的畫素全部塞到一臺 5.5 寸的 iPhone7 Plus 手機裡面去,那麼對於 40 寸的電視而言,每個畫素顆粒當然會大於 5.5 寸的手機的畫素。

resolution

所以對於設計師而言螢幕的解析度沒有太多的實際意義,還是得通過解析度計算實際的畫素密度(PPI)。

視口

viewport

在桌面瀏覽器中,視口是一個簡單的概念:視口就是瀏覽器的可視區域,也指瀏覽器的寬度。

但是在移動端,情況就變得複雜了,為了提供更好的網頁瀏覽感受,視口被分成了 佈局視口(layout viewport)視覺視口(visual viewport)理想視口(ideal viewport)

佈局視口

一個沒有對移動端做適配的網頁在手機瀏覽器中瀏覽,手機瀏覽器會盡可能的縮小網頁讓使用者看到全部的內容,比如下圖中的新浪新聞:

news.sina.com

這是因為瀏覽器廠商把視口寬度設定得很大,一般在 768px ~ 1024px 之間(一般是 980px,具體是由裝置自己決定)。所以在手機上,視口寬度與手機瀏覽器寬度(螢幕寬度)不再有關聯,而瀏覽器廠商定的視口被稱為 佈局視口

注意:佈局視口我們是看不見的,並且被縮放在螢幕內。比如說如果你建立一個 320px 寬的元素,那麼它在視口寬度設定為 980px 的手機瀏覽器中,只能佔據螢幕實際大小的 1/3 左右,效果如下圖所示:

news.sina.com

下圖列出了一些裝置上瀏覽器的預設視口寬度:

layout-viewport-default-width

我們可以通過 meta 視口標籤設定佈局視口的寬度:

<meta name="viewport" content="width=640">
複製程式碼

PS:JavaScript 中可以通過document.documentElement.clientWidth/height 程式碼獲得佈局視口的尺寸。

補充一點,CSS 裡面的 Media Queries(媒體查詢)指定的寬度就是佈局視口的寬度:

@media (min-width: 700px) {} /* 700px 指的就是佈局視口的寬度 */
複製程式碼

視覺視口

視覺視口是使用者正在看到的網頁區域,它和裝置的螢幕一樣寬,並且它的 CSS 畫素的數量會隨著使用者縮放而改變,也就是說縮放會影響視覺視口的大小。當縮放比為 100% 時,視覺視口與裝置螢幕一樣寬。放大會使得視覺視口變得更小,因為螢幕上顯示的 CSS 畫素更小了,而縮小會讓視覺視口更大,因為螢幕上的 CSS 畫素更多了。

注意一點,當使用者縮放時,只有視覺視口的尺寸會發生改變,佈局視口不會改變。移動端的縮放不會導致 CSS 佈局被重新計算(可能是出於效能的考慮)。

PS:JavaScript 中可以通過 window.innerWidth/Height 程式碼獲得視覺視口的尺寸。

var testDom = document.getElementById('test')

testDom.innerHTML = '螢幕寬度: ' + screen.width + '<br>視覺視口: ' + window.innerWidth + '<br>佈局視口: ' + document.documentElement.clientWidth

// 以下程式碼表示 3 秒後,頁面縮放從 100% 到 200%
setTimeout(function() {
  var metaDom = document.createElement('meta')

  metaDom.setAttribute('name', 'viewport')
  metaDom.setAttribute('content', 'initial-scale=2')
  document.querySelector('head').append(metaDom)
  testDom.innerHTML = '螢幕寬度: ' + screen.width + '<br>視覺視口: ' + window.innerWidth + '<br>佈局視口: ' + document.documentElement.clientWidth
}, 3000)
複製程式碼

理想視口

佈局視口在大多數情況下對使用者都是不友好的,雖然保留了網頁的完整性,但是犧牲了可用性,換句話說就是 佈局視口預設的寬度並不是一個理想的寬度。所以蘋果引入了理想視口的概念:理想視口對裝置來說最理想的佈局視口尺寸

可以通過下面的程式碼告訴瀏覽器使用它的理想視口:

<meta name="viewport" content="width=device-width">
複製程式碼

注意:

  • 理想視口的尺寸是由瀏覽器廠商決定的,開發者只能使用,而且同一裝置的不同瀏覽器可以有不同的尺寸
  • 不同裝置的相同瀏覽器理想視口尺寸也會不同(因為螢幕寬度不同,比如手機和平板)
  • 會隨著裝置轉向改變

PS:可以通過 screensiz 檢視相關裝置的理想視口尺寸。

縮放

對於縮放,首先要搞明白一點,縮放是相對於什麼來縮放的。

我們知道可以通過設定 meta 視口標籤的 initial-scale 來設定頁面的初始縮放值,那麼當我們如下設定後:

<meta name="viewport" content="initial-scale=1">
複製程式碼

佈局視口尺寸也會被設定為理想視口尺寸,相當於變相的設定了 width=device-width。由此,我們可以得到 縮放是相對於理想視口來進行 的結論。

layout-viewport-default-width

layout-viewport-default-width

如果要把佈局視口設定為理想視口,使用 width=device-widthinitial-scale=1 都可以實現,但這兩者有個相容問題,就是 iphone、ipad、IE 會橫豎屏不分,全部以豎屏的高度值作為理想視口的寬度。所以最好的設定方法是都寫上去,width=device-width 解決 IE 的問題,initial-scale=1 解決 iphone、ipad 的問題:

<meta name="viewport" content="width=device-width, initial-scale=1">
複製程式碼

縮放與裝置畫素、CSS 畫素的關係

縮放是在放大或縮小 CSS 畫素,對裝置畫素無影響。

比如一個寬度為 200px 的元素無論怎麼放大,都是 200 個 CSS 畫素,但是因為這些畫素被放大了,所以 CSS 畫素也就跨越了更多的裝置畫素。縮小則相反。

縮放與視口的關係

縮放會影響視覺視口的尺寸,但不會影響佈局視口的尺寸。

手機上頁面被使用者放大,視覺視口縮小,佈局視口不變,視覺視口內的 CSS 畫素數量減少;

手機上頁面被使用者縮小,視覺視口放大,佈局視口不變,視覺視口內的 CSS 畫素數量增多;

縮放比例

比如說在 iphone 中(理想視口寬度為 320px),如果我們設定 width=device-width, initial-scale=2,此時視覺視口的寬度會變為 160px,因為我們放大了一倍,視覺視口縮小了,1px 變得跟原來的 2px 長度一樣,所以放大一倍後,原來需要 320px 才能填滿的寬度只需要 160px 就能填滿。因此,我們可以得到一個公式:

視覺視口寬度 = 理想視口寬度 / 當前縮放比例

當前縮放比例 = 理想視口寬度 / 視覺視口寬度

禁止縮放

如果不希望使用者對網頁進行縮放操作,可以通過設定 user-scalable=no 來達到禁止縮放的效果。

總結

本篇文章主要介紹了移動端適配需要理解的幾個基礎概念,包括 畫素視口縮放,以及它們之間的相互關係。只有正確理解了這些概念才能很好的掌握移動端適配的方案及各種方案的工作機制,避免知其然不知其所以然的問題。

下一篇文章我們會詳細的介紹常見的四種移動端適配方案,請期待~

參考資料

相關文章