深刻淺出 Viewport 設計原理

Viewport 是 HTML5 針對移動端開發新增的一個 meta 屬性, 它的做用是爲同一網頁在不一樣設備的呈現,提供響應式解決方案。這篇文章嘗試經過按部就班的方式,逐層探索 Viewport 的設計原理,但願能給讀者帶來更加清晰、更加全面的技術認知。javascript

1、引言

在PC時代,咱們用 css 設置 1px 邊框,顯示器會用1個物理像素進行渲染。而進入移動應用時代後,咱們原來設置1px邊框,在手機上可能須要用 2 個或 3 個物理像素來渲染。css

那麼,手機爲何要這麼作?解決了什麼問題?以及咱們開發過程當中須要作什麼?html

下面,咱們將帶着這些問題來一步步探索移動端 Viewport 設計原理,以及如何利用 Viewport 進行移動端適配。java

2、基礎概念

一、屏幕尺寸

屏幕尺寸指的是手機屏幕對角線的長度,知道了屏幕的寬度(width)和高度(height),對角線就能夠經過勾股定理算出:web

 

而後再把這個長度換算成 「英寸(inch)」,就是咱們平時所說的手機尺寸。瀏覽器

1英寸等於 25.4mm,即:iphone

好比 iPhone 常見的尺寸有 3.5寸、4寸、4.7寸、5.5寸 等等。ide

二、物理像素

咱們在手機屏幕上看到的畫面,本質上都是由一個個發光的物理像素組成,物理像素是構成屏幕圖像的最小單元。佈局

咱們常說的屏幕分辨率,就是指這個屏幕上擁有多少個物理像素。字體

好比: iPhone4 的分辨率是 640 × 960,即屏幕在水平方向上有 640 個像素,在垂直方向上有 960 個像素。

一般,設計師給的 UI 設計稿上的 PX 指的就是物理像素。

三、像素密度 PPI

PPI(Pixel Per Inch by diagonal):表示對角線上每英寸所擁有的像素個數。

計算PPI,能夠簡單用勾股定理計算出對角線上的像素,再除以對角線長度:

將 iPhone 4 屏幕數據代入公式,便可得出 iPhone4 的 PPI :

PPI 的值越大,每英寸屏幕上的物理像素點就越多越密集,從而渲染出來的畫面也更加細膩、清晰。

好比,iphone3GS 和 iphone4 擁有相同大小的屏幕。但前者的分辨率是 320*480,能夠算出PPI爲 163,然後者的分辨率是 640*960, 其PPI是326。

這就致使 iphone4 在畫面呈現上比 iphone3GS 更加清晰和細膩。

四、PPI 致使的問題

咱們先看下面這兩張圖的區別是什麼?

 

很明細,左邊的圖要比右邊的看着舒服。

左邊的字體大小適中,圖片文字都能看的清楚,相比而言,右邊的字體就過小了,讓用戶閱讀變得困難。

那麼,這個問題是怎麼形成的呢?

咱們先來作一個對比實驗,以下圖所示:

左圖和右圖分別表明兩塊尺寸相同的屏幕,長度和寬度均爲 5cm,屏幕上的每一個方格表明一個物理像素點。

惟一不一樣的是,左邊屏幕分辨率爲5 × 5,而右邊屏幕分辨率爲 10 × 10 。

如今屏幕上放了一個按鈕,它的 css 樣式爲:

.button {
 width: 3px;
 height: 1px;
}

從圖上的效果能夠看出,雖然咱們爲兩個按鈕設置了相同的大小,但右屏上的按鈕比左屏上的按鈕小了不少。

因此咱們會發現,相同尺寸的屏幕,像素點越多,每一個物理像素點「自身」大小就越小,從而致使渲染出來的圖像就會越小。

也就是說,設置相同大小的樣式,屏幕的 PPI 越大,渲染出來的圖像就越小。

這實際上是一個問題。

在移動時代,手機的大小和分辨率良莠不齊,從而致使PPI也不盡相同。當咱們把一個web頁面放到PPI不一樣的設備上瀏覽時,就會出現「大小各異」的效果,違背了咱們對 css 樣式 「所見即所得」 的認知。

爲了讓同一個元素在全部設備上看起來都差很少大,設備廠商給顯示屏幕增長了 「縮放因子」。

五、縮放因子 DPR

這裏的縮放因子並非對圖像自己進行縮放,而是使用更多的像素來渲染同一個元素。

以下圖所示,一樣大小的矩形,在第一個設備上用過了 8×1 個物理像素來渲染,而在第二個設備上用了 16×2 個物理像素來渲染,在第三個設備上則用了 24×3 個物理像素來渲染。

這樣以來,同一個元素在全部設備上的顯示效果都同樣啦。

從圖上能夠看出,屏幕的PPI越大,縮放因子就越大。若是以第一個屏幕爲基準,這三個屏幕的縮放因子分別爲 一、二、3。

一般咱們把 「縮放因子」 叫作 DPR,DPR 是 device pixel ratio 的縮寫,即設備像素比。

這裏須要注意的是:

dpr 的大小並非經過固定公式計算出來的,而是廠商給屏幕設置的一個固定值,出廠時就肯定了,它的大小不會隨着程序的設置而改變。

六、DPR 和 PPI 的對應關係

不一樣平臺定義 dpr 的基線 PPI 是不一樣的。

因爲第一代 iPhone 的 PPI 是163,因此蘋果把 163 做爲縮放基線。

所以,在 iPhone 中, PPI=163 是1x 屏,PPI=326 是 2x 屏。

PPI 163 326 401 458
dpr 1 2 3 3
表明機型 iPhone3GS iPhone4 iPhone6P iPhoneX

而 Android 的縮放基線 PPI 是160,因此 PPI=160 是 1x 屏,PPI=320 是 2x 屏。

從圖中能夠看出: 

dpr 的大小和 PPI 正相關,但不成正比,咱們沒法經過特定的公式來計算它的大小。

七、邏輯像素和邏輯分辨率

對於同一個元素,dpr 越大,屏幕所須要的物理像素就越多,這是咱們上面得出的結論。

那麼,在軟件程序中,元素的大小到底應該寫成多少px?

爲了解決這個問題,咱們引入了 「邏輯像素」 的概念,即 css 中寫的 px 。

所謂邏輯像素,就是它的大小和物理像素不是一一對應的。

假設,咱們如今設置一個元素的css樣式以下:

.el {
  width: 8px;
  height: 1px;
}

那麼,這個元素在不一樣屏幕上渲染方式是不一樣的:

  

在 dpr=1 的屏幕上,1個邏輯像素對應1個物理像素。

在 dpr=2 的屏幕上,1個邏輯像素須要對應2個物理像素,才能保證元素同等大小。

同理,在 dpr=3 的屏幕上,1個邏輯像素對應3個物理像素,才能保證元素同等大小。

所以,咱們能夠得出一個結論:

一個邏輯像素在不一樣屏幕上所表示的物理像素數是不一樣的,它的大小和 dpr 一一對應。

有了這個理論,咱們就能推導出屏幕的邏輯分辨率,也就是屏幕的 「邏輯寬度」 和 「邏輯高度」。

好比 iPhone6 的物理分辨率爲 750 × 1334,dpr = 2, 帶入公式就能夠得出其邏輯分辨率:

屏幕的邏輯分辨率也能夠經過 DOM API 來獲取:

// iPhone6
window.screen.width; // 375px
window.screen.height; // 667px;

一般,咱們在 CSS 中設置的元素尺寸,本質上都是基於邏輯分辨率進行佈局的。

八、iPhone 常見的幾種規格

設備 邏輯分辨率(point) 物理分辨率(pixel) 屏幕尺寸 dpr PPI
iPhone 3GS 320 × 480 320 × 480 3.5 1 163
iPhone 4 320 × 480 640 × 960 3.5 2 326
iPhone 5 320 × 568 640 × 1136 4.0 2 326
iPhone 6 375 × 667 750 × 1334 4.7 2 326
iPhone 6 Plus 414 × 736 1080 × 1920 5.5 3 401
iPhone X 375 × 812 1125 × 2436 5.8 3 458
iPhoneXR 414 × 896 828 × 1792 6.1 2 326
iPhoneXS Max 414 × 896 1242 × 2688 6.5 3 458

3、Viewport

一、Viewport 究竟是什麼?

咱們在寫H5頁面的時候,一般會在 html 的 head 中加入下面這句話:

這句話就是在設置頁面的 viewport 。那 viewport 究竟是什麼?爲何要設置它?

簡單來講:viewport 是屏幕背後的一張畫布。

下面,咱們將逐個理解 viewport 中的每一個概念:

二、Viewport 畫布

瀏覽器會先把頁面內容繪製到畫布上,而後再經過屏幕窗口呈現出來。

畫布的寬度可大可小, 當畫布的寬度大於屏幕寬度時,畫布上的內容就沒法經過屏幕所有展現出來,用戶能夠經過屏幕手勢來拖動畫布查看被遮擋的部分。

若是沒有在 html 中加 viewport 的設置,畫布其實也是存在的,瀏覽器會給畫布設置一個默認寬度 ,不一樣平臺的默認值以下:

畫布的寬度能夠經過 DOM API 來獲取:

三、device-width 指的是什麼?

device-width 指屏幕可視窗口在水平方向上的邏輯像素。

device-width 的大小能夠經過 window.screen.width 來獲取:

四、width=device-width 在設置誰的寬度?

width 指的是畫布的寬度,device-width 是可視窗口寬度。

width=device-width 就是把畫布的寬度設置爲可視窗口的寬度,讓畫布上的內容徹底呈現出來。

設置了 width=device-width 以後,畫布的寬度就和屏幕的寬度同樣大了。

五、畫布縮放 - scale

scale 是指畫布以 device-width 大小爲基準的縮放值。

initial-scale=1.0 也就至關於設置了 width=device-width

一般須要同時設置這兩個值,這是由於二者在不一樣平臺有兼容性問題:

在iPhone 和 iPad 上,只支持 inital-scale=1 的設置,而在 IE 只支持width=device-width ,因此二者同時設置能夠兼容全部的平臺。

六、動態縮放機制

在沒有給頁面設置 viewport 的狀況下,當畫布寬度大於可視窗口的時候,瀏覽器會自動對畫布進行縮放,以適配可視窗口大小。這樣頁面在不滾動的狀況下也能呈現所有內容。

下面這個頁面是PC端頁面,沒有作移動端適配,能夠看出網頁的內容依然能夠徹底呈現出來,這是由於沒有設置 viewport 而觸發了 畫布的動態縮放機制。

經過 DOM API 能計算出瀏覽器確實對畫布進行了縮放:

須要注意的是:

當沒有設置 viewport 或者 設置了viewport 但沒有設置 scale 的時候,纔會觸發瀏覽器動態縮放機制。

七、禁止動態縮放

給頁面添加 viewport 設置,以下所示:

因爲手動設置了 scale 的值,沒有觸發自動縮放機制,瀏覽器直接把寬度爲 980px 的畫布原封不動的展現出來了:

這種狀況下須要經過滾動才能查看畫布所有內容。

八、三個 Viewport

一般,咱們把畫布稱爲 layout viewport, 把屏幕可視窗口稱爲 visual viewport。

而把設置 width=device-width 的畫布稱爲 ideal viewport,即「理想視口」。

咱們一般在 html 中設置 viewport 就是爲了獲得理想視口,方便用戶閱覽。

4、響應式佈局方案

響應式佈局的目標是:用同一套代碼適配全部的設備。

經常使用的佈局方案有如下幾種:

  • 百分比
  • vw
  • Css Media Query
  • rem
  • flex box

下面是手淘團隊移動端適配的協做模式:

設計師通常會把 iPhone6(750px) 做爲設計稿,設計稿中的元素也都是基於750px進行標註的,固然這裏的 px 指的是物理像素。

開發拿到設計稿後,根據iPhone6的 dpr 把標註中的元素大小換算成 css 中的大小,好比設計稿中按鈕的寬度標註爲40px, 則 css 中應該寫成40/2=20px

而後再根據屏幕的邏輯寬度進行同步縮放(如:rem/vw 方案),就能夠實現向上或向下適配全部設備。

5、總結

最後,咱們再回顧一下開篇提到的問題,其實不難理解,這是因爲屏幕的 dpr 不一樣致使的。

通常狀況下,PC 屏幕 dpr 是 1,即 1個邏輯像素 = 1個物理像素,而移動端的 dpr 一般都是 2 或 3,所以也就須要 2個或3個物理像素來渲染。

這也是 「移動端1px邊框」 的經典問題,理解了 viewport,這個問題就不難解決了。

原創發佈 @一像素 2020

相關文章
相關標籤/搜索