在 PC 端,視口指的是瀏覽器的可視區域,其寬度和瀏覽器視窗的寬度保持一致。在 CSS 標準文件中,視口也被稱為初始包含塊,它是所有 CSS 百分比寬度推算的根源,給 CSS 佈局限制了一個最大寬度。
而移動端則較為複雜,它涉及到三個視口:佈局視口(Layout Viewport)、視覺視口(Visual Viewport)和理想視口(Ideal Viewport)。
本文主要討論移動端中的視口。
1. 基本概念
1.1 兩種畫素
畫素是計算機螢幕中顯示特定顏色的最小區域。螢幕中的畫素越多,同一範圍內能看到的內容就越多。或者說,當裝置尺寸相同時,畫素越密集,畫面就越精細。
那麼,當我們在 CSS 中為一個元素設定屬性 width: 250px;
時,會發生什麼?這個元素的寬度究竟是多少畫素呢?
事實上,這裡已經涉及了兩種不同的畫素:物理畫素和 CSS 畫素。
物理畫素(裝置畫素,device pixels)
指的是裝置螢幕的物理畫素,任何裝置的物理畫素數量都是固定的。
CSS 畫素(CSS pixels)
是 CSS 和 JS 中使用的一個抽象概念。它和物理畫素之間的比例取決於螢幕的特性(是否為高密度)以及使用者進行的縮放,由瀏覽器自行換算。
在 Apple 的視網膜屏(Retina)中,每 4 個畫素為一組,渲染出普通螢幕中一個畫素顯示區域內的影像,從而實現更為精細的顯示效果。此時, 250px 的元素跨越了 500 個物理畫素的寬度。
如果使用者進行了放大,那麼一個 CSS 畫素還將跨越更多的物理畫素。
1.2 三種視口
移動端瀏覽器通常寬度是 240px~640px,而大多數為 PC 端設計的網站寬度至少為 800px,如果仍以瀏覽器視窗作為視口的話,網站內容在手機上看起來會非常窄。
因此,引入了佈局視口、視覺視口和理想視口三個概念,使得移動端中的視口與瀏覽器寬度不再相關聯。
佈局視口(layout viewport)
一般移動裝置的瀏覽器都預設設定了一個 viewport 元標籤,定義一個虛擬的佈局視口(layout viewport),用於解決早期的頁面在手機上顯示的問題。iOS, Android 基本都將這個視口解析度設定為 980px,所以 PC 上的網頁基本能在手機上呈現,只不過元素看上去很小,一般預設可以通過手動縮放網頁。
佈局視口的寬度/高度可以通過 document.documentElement.clientWidth / Height
獲取。
可以看到,預設的佈局視口寬度為 980px。如果要顯式設定佈局視口,可以使用 HTML 中的 meta 標籤:
<meta name="viewport" content="width=400">
佈局視口使視口與移動端瀏覽器螢幕寬度完全獨立開。CSS 佈局將會根據它來進行計算,並被它約束。
視覺視口(visual viewport)
視覺視口是使用者當前看到的區域,使用者可以通過縮放操作視覺視口,同時不會影響佈局視口。
視覺視口和縮放比例的關係為:
當前縮放值 = 理想視口寬度 / 視覺視口寬度
所以,當使用者放大時,視覺視口將會變小,CSS 畫素將跨越更多的物理畫素。
理想視口(ideal viewport)
佈局視口的預設寬度並不是一個理想的寬度,於是 Apple 和其他瀏覽器廠商引入了理想視口的概念,它對裝置而言是最理想的佈局視口尺寸。顯示在理想視口中的網站具有最理想的寬度,使用者無需進行縮放。
理想視口的值其實就是螢幕解析度的值,它對應的畫素叫做裝置邏輯畫素(device independent pixel, dip)。dip 和裝置的物理畫素無關,一個 dip 在任意畫素密度的裝置螢幕上都佔據相同的空間。如果使用者沒有進行縮放,那麼一個 CSS 畫素就等於一個 dip。
用下面的方法可以使佈局視口與理想視口的寬度一致:
<meta name="viewport" content="width=device-width">
實際上,這就是響應式佈局的基礎。
2. 視口的設定
我們可以使用視口元標籤(viewport meta 標籤)來進行佈局視口的設定。
<meta name="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=1">
下面是每個屬性的詳細說明:
屬性名 | 取值 | 描述 |
---|---|---|
width | 正整數或device-width | 定義視口的寬度,單位為畫素 |
height | 正整數或device-height | 定義視口的高度,單位為畫素,一般不用 |
initial-scale | [0.0-10.0] | 定義初始縮放值 |
minimum-scale | [0.0-10.0] | 定義放大最大比例,它必須小於或等於maximum-scale設定 |
maximum-scale | [0.0-10.0] | 定義縮小最小比例,它必須大於或等於minimum-scale設定 |
user-scalable | yes / no | 定義是否允許使用者手動縮放頁面,預設值 yes |
有幾點值得注意:
- viewport 標籤只對移動端瀏覽器有效,對 PC 端瀏覽器是無效的
- 當縮放比例為 100% 時,dip 寬度 = CSS 畫素寬度 = 理想視口的寬度 = 佈局視口的寬度
- 單獨設定 initial-scale 或 width 都會有相容性問題,所以設定佈局視口為理想視口的最佳方法是同時設定這兩個屬性
- 即使設定了 user-scalable = no,在 Android Chrome 瀏覽器中也可以強制啟用手動縮放
3. 一倍圖、二倍圖、三倍圖
MacBook Pro 視網膜屏(Retina)顯示器硬體畫素是 2880px * 1800px。當設定螢幕解析度為 1920px * 1200px 的時候,理想視口的寬度值是 1920px, 那麼 dip 的寬度值就是 1920px。其與理想視口寬度的比值為1.5(2880/1920),這個比值叫做裝置畫素比:
邏輯畫素寬度 * 裝置畫素比 = 物理畫素寬度
裝置畫素比可以通過 window.devicePixelRatio
來獲取,或者使用 CSS 中的 device-pixel-ratio
。
下面是常見的裝置畫素比:
- 普通密度桌面螢幕:
devicePixelRatio = 1
- 高密度桌面螢幕(Mac Retina):
devicePixelRatio = 2
- 主流手機螢幕:
devicePixelRatio = 2 or 3
對於一張 100px * 100px 的圖片,通過 CSS 設定其寬高:
{
width:100px;
height:100px;
}
在普通螢幕的電腦中開啟是正常的,但假設在手機或 Retina 屏中開啟,按照邏輯解析度來渲染,他們的 devicePixelRatio = 2
,那麼就相當於拿 4 個物理畫素來描繪 1 個電子畫素。這等於拿一個2倍的放大鏡去看圖片,圖片就會變得模糊。
這時,就需要使用 @2x 甚至 @3x 圖來避免圖片的失真。
最後,本文僅涉及了移動端開發中視口的基本概念,具體細節可以參考 PPK 的大作《移動Web手冊》
PS:電子版可關注公眾號《程式碼寫完了》,傳送”ppk”獲取