三個 viewport
ppk大神對于移動設(shè)備上的 viewport 有著非常多的研究(第一篇,第二篇,第三篇),有興趣的同學(xué)可以去看一下。ppk認為,移動設(shè)備上有三個 viewport。
viewport簡介
viewport 特性,一個移動專屬的Meta值,用于定義視口的各種行為。
該特性最先由Apple引入,用于解決移動端的頁面展示問題,后續(xù)被越來越多的廠商跟進。
舉個簡單的例子來講為什么會需要它:
我們知道用戶大規(guī)模使用手機等移動設(shè)備來進行網(wǎng)頁瀏覽器,其實得益于智能手持設(shè)備的興起,也就是近幾年的事。(還記得不久前的幾年,滿大街都還是諾基亞的天下么?)
這時有一個很現(xiàn)實的問題擺在了廠商面前,用戶并不能很好地通過手機等設(shè)備訪問網(wǎng)頁,因為屏幕太小。
Apple也發(fā)現(xiàn)了這個問題,并且適時的出現(xiàn),它提出了一個方案用來解決這個問題。在iOS Safari中定義了一個 viewport meta 標(biāo)簽,用來創(chuàng)建一個虛擬的布局視口(layout viewport),而這個視口的分辨率接近于PC顯示器,Apple將其定義為 980px。
布局視窗(layout viewport)
移動設(shè)備上的瀏覽器認為自己必須能讓所有的網(wǎng)站都正常顯示,即使是那些不是為移動設(shè)備設(shè)計的網(wǎng)站。但如果以瀏覽器的可視區(qū)域作為 viewport 的話,因為移動設(shè)備的屏幕都不是很寬,所以那些為桌面瀏覽器設(shè)計的網(wǎng)站放到移動設(shè)備上顯示時,必然會因為移動設(shè)備的 viewport 太窄,而擠作一團,甚至布局什么的都會亂掉。也許有人會問,現(xiàn)在不是有很多手機分辨率都非常大嗎,比如768x1024,或者 1080x1920 這樣,那這樣的手機用來顯示為桌面瀏覽器設(shè)計的網(wǎng)站是沒問題的吧?前面我們已經(jīng)說了,css中的1px并不是代表屏幕上的1px,你分辨率越大,css中1px代表的物理像素就越多,devicePixelRatio的值也越大,這很好理解,因為你分辨率增大了,但屏幕尺寸并沒有變大多少,必須讓css中的1px代表更多的物理像素,才能讓1px的東西在屏幕上的大小與那些低分辨率的設(shè)備差不多,不然就會因為太小而看不清。所以在 1080x1920 這樣的設(shè)備上,在默認情況下,也許你只要把一個div的寬度設(shè)為300多px(視devicePixelRatio的值而定),就是滿屏的寬度了。回到正題上來,如果把移動設(shè)備上瀏覽器的可視區(qū)域設(shè)為 viewport 的話,某些網(wǎng)站就會因為 viewport 太窄而顯示錯亂,所以這些瀏覽器就決定默認情況下把 viewport 設(shè)為一個較寬的值,比如980px,這樣的話即使是那些為桌面設(shè)計的網(wǎng)站也能在移動瀏覽器上正常顯示了。瀏覽器默認的 viewport 叫做 layout viewport。
布局視窗表示的是瀏覽器默認的 viewport,一般情況下這個寬度要大于瀏覽器可視區(qū)域?qū)挾取?/p>
這是一個虛擬的窗口,其大小比手機屏幕大,加載網(wǎng)頁時,直接把HTML渲染在這個虛擬的窗口中,這樣就不會樣式錯亂了。在查看的時候,畢竟手機的 visual viewport 小啊,那就只能通過滾動條來看了。

打個比喻,layout viewport 就是一張大白紙,HTML的內(nèi)容就寫在這個大白紙上,visual viewport 就是一個放大鏡,上下左右移動,可以顯示其中的一部分。
layout viewport 的寬度可以通過 document.documentElement.clientWidth 來獲取。
視覺視窗(visual viewport)
所謂的視覺視窗說白了就是設(shè)備的屏幕區(qū)域,換句話說就是用戶通過屏幕所看到的頁面內(nèi)容。但它所對應(yīng)的并不是指屏幕區(qū)域里的物理像素,而是CSS 像素。并且它所包含的 CSS 像素的數(shù)量也是隨著用戶縮放而有所改變。
visual viewport 的尺寸不會是一個固定的值,甚至每款設(shè)備都可能不同。大致列幾種常見設(shè)備的 visual viewport 尺寸:
- iPhone4~iPhone5S: 320*480px
- iPhone6~iPhone6S: 375*627px
- iPhone6 Plus~iPhone6S Plus: 414*736px
以 iPhone4S 為例,會在其 320px 的 visual viewport 上,創(chuàng)建一個寬 980px 的 layout viewport,于是用戶可以在 visual viewport 中拖動或者縮放網(wǎng)頁,來獲得良好的瀏覽效果;布局視口用來配合CSS渲染布局,當(dāng)我們定義一個容器的寬度為100%時,這個容器的實際寬度是 980px 而不是 320px,通過這種方式大部分網(wǎng)頁就能以縮放的形式正常顯示在手機屏幕上了。
然而,layout viewport 的寬度是大于瀏覽器可視區(qū)域的寬度的,所以我們還需要一個 viewport 來代表瀏覽器可視區(qū)域的大小,把這個 viewport 叫做 visual viewport。visual viewport 的寬度可以通過 window.innerWidth 來獲取。

理想視窗(ideal viewport)
已經(jīng)有兩個 viewport 了:layout viewport 和 visual viewport。但瀏覽器覺得還不夠,因為現(xiàn)在越來越多的網(wǎng)站都會為移動設(shè)備進行單獨的設(shè)計,所以必須還要有一個能完美適配移動設(shè)備的 viewport。所謂的完美適配指的是,首先不需要用戶縮放和橫向滾動條就能正常的查看網(wǎng)站的所有內(nèi)容;第二,顯示的文字的大小是合適,比如一段14px大小的文字,不會因為在一個高密度像素的屏幕里顯示得太小而無法看清,理想的情況是這段14px的文字無論是在何種密度屏幕,何種分辨率下,顯示出來的大小都是差不多的。當(dāng)然,不只是文字,其他元素像圖片什么的也是這個道理。這個 viewport 就是 ideal viewport - 移動設(shè)備的理想 viewport。
ideal viewport 并沒有一個固定的尺寸,不同的設(shè)備擁有有不同的 ideal viewport。所有的 iphone 的 ideal viewport 寬度都是320px,無論它的屏幕寬度是 320 還是 640,也就是說,在 iphone 中,css中的 320px 就代表iphone 屏幕的寬度。
viewport 分為 layout viewport、 visual viewport 和 ideal viewport 三類,其中的 ideal viewport 是最適合移動設(shè)備的 viewport,ideal viewport 的寬度等于移動設(shè)備的屏幕寬度,只要在css中把某一元素的寬度設(shè)為 ideal viewport 的寬度(單位用px),那么這個元素的寬度就是設(shè)備屏幕的寬度了,也就是寬度為100%的效果。ideal viewport 的意義在于,無論在何種分辨率的屏幕下,那些針對 ideal viewport 而設(shè)計的網(wǎng)站,不需要用戶手動縮放,也不需要出現(xiàn)橫向滾動條,都可以完美的呈現(xiàn)給用戶。
利用meta標(biāo)簽對viewport進行控制
移動設(shè)備默認的 viewport 是 layout viewport,也就是那個比屏幕要寬的 viewport,但在進行移動設(shè)備網(wǎng)站的開發(fā)時,我們需要的是 ideal viewport。那么怎么才能得到 ideal viewport 呢?這就該輪到meta標(biāo)簽出場了。
在開發(fā)移動設(shè)備的網(wǎng)站時,最常見的的一個動作就是把下面這個東西復(fù)制到我們的head標(biāo)簽中:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
該 meta 標(biāo)簽的作用是讓當(dāng)前 viewport 的寬度等于設(shè)備的寬度(ideal viewport),同時不允許用戶手動縮放。也許允不允許用戶縮放不同的網(wǎng)站有不同的要求,但讓 viewport 的寬度等于設(shè)備的寬度,這個應(yīng)該是大家都想要的效果,如果你不這樣的設(shè)定的話,那就會使用那個比屏幕寬的默認 viewport,也就是說會出現(xiàn)橫向滾動條。
meta viewport 標(biāo)簽首先是由蘋果公司在其safari瀏覽器中引入的,目的就是解決移動設(shè)備的 viewport 問題。后來安卓以及各大瀏覽器廠商也都紛紛效仿,引入對 meta viewport 的支持,事實也證明這個東西還是非常有用的。
在蘋果的規(guī)范中,meta viewport 有6個屬性:

要把當(dāng)前的 viewport 寬度設(shè)為 ideal viewport 的寬度,既可以設(shè)置 width=device-width,也可以設(shè)置 initial-scale=1,但這兩者各有一個小缺陷,就是 iphone、ipad 以及IE 會橫豎屏不分,通通以豎屏的 ideal viewport 寬度為準。所以,最完美的寫法應(yīng)該是,兩者都寫上去,這樣就 initial-scale=1 解決了 iphone、ipad 的毛病,width=device-width 則解決了IE的毛?。?/p>
<meta name="viewport" content="width=device-width, initial-scale=1">
總結(jié) :
第一、如果不設(shè)置 meta viewport 標(biāo)簽,那么移動設(shè)備上瀏覽器默認的寬度值為800px,980px,1024px等這些,總之是大于屏幕寬度的。這里的寬度所用的單位px都是指css中的px,它跟代表實際屏幕物理像素的px不是一回事。
第二、每個移動設(shè)備瀏覽器中都有一個理想的寬度,這個理想的寬度是指css中的寬度,跟設(shè)備的物理寬度沒有關(guān)系,在css中,這個寬度就相當(dāng)于100%的所代表的那個寬度。我們可以用 meta 標(biāo)簽把 viewport 的寬度設(shè)為那個理想的寬度,如果不知道這個設(shè)備的理想寬度是多少,那么用 device-width 這個特殊值就行了,同時 initial-scale=1 也有把 viewport 的寬度設(shè)為理想寬度的作用。所以,我們可以使用
<meta name="viewport" content="width=device-width, initial-scale=1">
來得到一個理想的 viewport(也就是前面說的 ideal viewport )。
為什么需要有理想的 viewport 呢?比如一個分辨率為 320x480 的手機理想viewport 的寬度是 320px,而另一個屏幕尺寸相同但分辨率為 640x960 的手機的理想 viewport 寬度也是為 320px,那為什么分辨率大的這個手機的理想寬度要跟分辨率小的那個手機的理想寬度一樣呢?這是因為,只有這樣才能保證同樣的網(wǎng)站在不同分辨率的設(shè)備上看起來都是一樣或差不多的。實際上,現(xiàn)在市面上雖然有那么多不同種類不同品牌不同分辨率的手機,但它們的理想 viewport 寬度歸納起來無非也就 320、360、384、400等幾種,都是非常接近的,理想寬度的相近也就意味著我們針對某個設(shè)備的理想 viewport 而做出的網(wǎng)站,在其他設(shè)備上的表現(xiàn)也不會相差非常多甚至是表現(xiàn)一樣的。