在閱讀這篇文章之前,你需要了解設備像素、邏輯像素(設備獨立像素)和CSS像素的區(qū)別,見我的前一篇文章。
layout viewport
layout viewport是網(wǎng)頁布局的區(qū)域,它是<html>元素的父容器。只要你不在css中修改<html>元素的寬度,<html>元素的寬度就會撐滿layout viewport的寬度。
很多時候瀏覽器窗口沒有辦法顯示出layout viewport的全貌,但是它確實是已經被加載出來了,這個時候滾動條就出現(xiàn)了,你需要通過滾動條來瀏覽layout viewport其他的部分。
layout viewport用css像素來衡量尺寸,在縮放、調整瀏覽器窗口的時候不會改變。縮放、調整瀏覽器窗口改變的只是visual viewport。
在桌面瀏覽器中,縮放為100%的時候,Layout Viewport寬度等于內容窗口的寬度。(你幾乎不會在電腦上見過橫向滾動條,除非你調整縮放)
但是在移動端,縮放為100%的時候,Layout Viewport不一定等于內容窗口的大小。當你用手機瀏覽瀏覽寬大的網(wǎng)頁(這些網(wǎng)頁沒有采用響應式設計)的時候,你只能一次瀏覽網(wǎng)頁的一個部分,然后通過手指滑動瀏覽其他部分。這就說明整個網(wǎng)頁(Layout Viewport)已經加載出來了,只不過你要一部分一部分地看。

不要以為所有元素的位置都會在layout viewport的內部,你將body的一個子元素添加out類:
.out {
position: absolute;
right: -30px;
background-color: red;
}
這個元素就會超出layout viewport 30px!
visual viewport
visual viewport就是顯示在屏幕上的網(wǎng)頁區(qū)域。通過前面的說明你應該已經知道visual viewport了:它往往只顯示layout viewport的一部分。visual viewport就像一臺攝像機,layout viewport就像一張紙,攝像機對準紙的哪個部分,你就能看見哪個部分。你可以改變攝像機的拍攝區(qū)域大?。ㄕ{整瀏覽器窗口大?。?,也可以調整攝像機的距離(調整縮放比例),這些方法都可以改變visual viewport,但是layout viewport始終不變。
visual viewport用css像素來衡量尺寸,表示有多少個css像素能夠被用戶看到。

舉個栗子:
為了讓小小的手機屏幕也能夠瀏覽寬大的網(wǎng)頁(這些網(wǎng)頁沒有采用響應式設計),手機瀏覽器將layout viewport的默認寬度設為與電腦瀏覽器一樣,比如980px,1024px(單位:CSS像素)。由于手機的屏幕邏輯像素寬度一般只有300~400邏輯像素,因此需要將多個css像素由1個邏輯像素顯示(也就是縮小,千萬不要忘記縮放比例=css像素邊長/邏輯像素邊長),讓手機屏幕顯示的css像素與網(wǎng)頁的css像素一樣多了,也就是visual viewport = layout viewport。

但是這會引發(fā)一個問題:字體小得難以閱讀。為了方便閱讀我們又不得不用手指將縮放調整到100%左右(一個設備獨立像素顯示一個css像素,對于我的手機來說,水平方向只有360個設備獨立像素),這個時候visual viewport 只顯示layout viewport的一部分了。

我們做前端開發(fā)一定要為移動端瀏覽器進行適配,也就是進行響應式設計。響應式設計的第一步就是在html中加入:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
這個標簽只對移動端瀏覽器生效,它將layout viewport的橫向css像素數(shù)量設為屏幕的橫向dips(定值),然后將初始縮放的值設為1.0,也就是讓css像素的大小=dips的大小。這樣,數(shù)值、單位都想等了,網(wǎng)頁寬度也就等于屏幕寬度了,也不會出現(xiàn)橫向滾動條。
dips是設備獨立像素的縮寫。設備獨立像素也叫邏輯像素。

可以看出,現(xiàn)在的字體大小合適了。網(wǎng)頁的排版變化了,和電腦版的網(wǎng)頁差別很明顯。排版變化的原因是網(wǎng)站使用了媒體查詢:在加載css的時候檢測顯示設備的屬性,為不同的設備屬性應用不同的樣式。
相關屬性
1. screen.width/height
上一篇文章說過的screen.width/height:整個屏幕的寬度和高度。這兩個數(shù)值的單位是設備獨立像素。這兩個數(shù)值不隨頁面縮放、瀏覽器窗口大小而改變,在前端開發(fā)的過程中可以認為是固定不變的(除非你通過操作系統(tǒng)改變屏幕的分辨率)。這兩個數(shù)值是操作系統(tǒng)決定的,由于設備獨立像素比設備像素經常不等于1:1,實際屏幕物理像素的分辨率不一定是screen.width×screen.height。

在上圖中列出了iphone各個手機的設備分辨率和IOS決定的分辨率(邏輯分辨率),我們只需要看這兩行。
設備分辨率就是屏幕上的物理像素的數(shù)量,當手機廠商宣傳自己的屏幕有多么清晰銳利的時候,相互攀比的就是這個數(shù)值。
邏輯分辨率就是screen.width/height。為什么iphone3GS以后的iphone都要把這個值設為實際屏幕分辨率的1/2或1/3呢?因為隨著屏幕上塞進越來越多的真實像素,屏幕大小的變化卻不那么明顯,因此像素密度也越來越高。如果還讓邏輯分辨率:真實屏幕分辨率=1:1,那么12px的字體就會越來越小,影響閱讀體驗。因此,后續(xù)的iphone用4個真實像素(甚至9個像素)組合成一個“邏輯像素”。這樣,即使真實像素越來越小,每一個“邏輯像素”的大小變化不大。瀏覽器可以放心地使用邏輯像素來衡量大小,而不用擔心真實大小在不同的顯示器上出現(xiàn)嚴重偏差。
2. window.innerWidth/Height
visual viewport的大小,也就是瀏覽器內容窗口的大小,不包括菜單欄、地址欄、狀態(tài)欄等,但是包括滾動條。單位是CSS像素。通過這個屬性你可以知道,當前的瀏覽器窗口可以容納多少個css像素。當用戶放大的時候這個數(shù)值會減少(因為css像素變大了),當用戶縮小的時候這個數(shù)值增大。縮放改變?yōu)g覽器窗口都會改變這個屬性的值。

Opera瀏覽器是例外,其單位是設備獨立像素,也就是說如果你只調整縮放,這兩個值不會改變。
與之對應的,window.outerWidth/outerHeight給出整個瀏覽器窗口的大小(包括各種欄),但是單位是設備獨立像素。
3. document.documentElement.clientWidth/Height
Layout Viewport的尺寸(Layout Viewport是<html>元素的父容器),單位是CSS像素。
它與window.innerWidth/Height的唯一區(qū)別是,document.documentElement.clientWidth/Height不包含滾動條。
document.documentElement指的是html元素,通常Element.clientWidth應該給出元素的大小,但是document.documentElement.clientWidth/Height并不衡量html元素的大小,這是一個特例。
4. document.documentElement.offsetWidth/Height
<html>元素的尺寸,除非你在css中改變html的大?。ê苌儆腥诉@么做),否則html的寬度始終與Layout Viewport寬度相同。單位是CSS像素。
5. window.pageX/YOffset
滾動距離,描述用戶已經向右、向下滾動了多少個像素,也可以理解為visual viewport相對于layout viewport的偏移值。單位是CSS像素。

當用戶進行縮放的時候,瀏覽器會盡量保證:原先在內容區(qū)頂部的元素,在縮放以后依然在內容區(qū)頂部,看以下例子:
放大前
放大后
原本數(shù)字3在頂部,放大后3依然在頂部。window.pageYOffset大致相同。大致相同的原因是CSS像素數(shù)量不隨著縮放而變化,原本在上方的內容高度有多少個CSS像素,放縮以后依然是多少個CSS像素。至于為什么不是完全相同,是因為"原先在內容區(qū)頂部的元素,在縮放以后依然在內容區(qū)頂部"這一機制無法完美地做到。
以下是測試用的代碼,可以自己改動試試看(在電腦上使用chrome可以模擬不同的移動設備來調試,在開發(fā)者工具點擊右上角的“toggle device toolbar”即可)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!--<link rel="stylesheet" href="test.css" type="text/css" />-->
<title>test viewport</title>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.box {
width: 100%;
height: 200px;
background-color: greenyellow;
}
.out {
position: absolute;
right: -30px;
background-color: rosybrown;
}
</style>
</head>
<body>
<div class="box">box</div>
<div class="out">out</div>
</body>
</html>
謝謝閱讀!后續(xù)我會更新更多有關響應式設計的內容!

