深入淺出viewport

開發(fā)移動網(wǎng)頁時,你一定會遇到下面這段代碼:

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes" />

在網(wǎng)頁的<head>中增加以上這句話,可以讓網(wǎng)頁的寬度自動適應(yīng)手機(jī)屏幕的寬度。其中:

width=device-width :表示寬度是設(shè)備屏幕的寬度
initial-scale=1.0:表示初始的縮放比例
minimum-scale=0.5:表示最小的縮放比例
maximum-scale=2.0:表示最大的縮放比例
user-scalable=yes:表示用戶是否可以調(diào)整縮放比例

懂了嗎?沒懂?!好,繼續(xù)往下看,保證你懂。

設(shè)備像素和CSS像素

你需要明白的第一個概念是CSS像素,以及它和設(shè)備像素的區(qū)別。

設(shè)備像素是我們直覺上覺得「靠譜」的像素。這些像素為你所使用的各種設(shè)備都提供了正規(guī)的分辨率,并且其值可以(通常情況下)從screen.width/height屬性中讀出。

如果你給一個元素設(shè)置了width: 128px的屬性,并且你的顯示器是1024px寬,當(dāng)你最大化你的瀏覽器屏幕,這個元素將會在你的顯示器上重復(fù)顯示8次(大概是這樣;我們先忽略那些微妙的地方)。

如果用戶進(jìn)行縮放,那么計算方式將會發(fā)生變化。如果用戶放大到200%,那么你的那個擁有width: 128px屬性的元素在1024px寬的顯示器上只會重復(fù)顯示4次。

現(xiàn)代瀏覽器中實現(xiàn)縮放的方式無怪乎都是「拉伸」像素。所以,元素的寬度并沒有從128個像素被修改為256個像素;相反是實際像素被放大了兩倍。形式上,元素仍然是128個CSS像素寬,即使它占據(jù)了256個設(shè)備像素的空間。

換句話說,放大到200%使一個CSS像素變成為一個設(shè)備像素的四倍。(寬度2倍,高度2倍,總共4倍)

一些配圖可以解釋清楚這個概念。這兒有四個100%縮放比的元素。這兒沒有什么值得看的;CSS像素與設(shè)備像素完全重疊。

1

現(xiàn)在讓我們縮小。CSS像素開始收縮,這意味著現(xiàn)在一個設(shè)備像素覆蓋了多個CSS像素。

2

如果你進(jìn)行放大,相反的行為會發(fā)生。CSS像素開始變大,現(xiàn)在一個CSS像素覆蓋了多個設(shè)備像素。

3

這兒的要點是你只對CSS像素感興趣。這些就是那些控制你的樣式表如何被渲染的像素。

設(shè)備像素對你(譯者:指的是開發(fā)者)來說基本上沒用。但是對于用戶不一樣;用戶將會放大或者縮小頁面直到他能舒服的閱讀為止。無論怎樣,縮放比例對你不會產(chǎn)生影響。瀏覽器將會自動的使你的CSS布局被拉伸或者被壓縮。

100%縮放

我是以假設(shè)縮放比例為100%來開始這個例子的。是時候需要更加嚴(yán)格的來定義一下這個100%了:

在縮放比例100%的情況下一個CSS像素完全等于一個設(shè)備像素。

100%縮放的概念在接下來的解釋中會非常有用,但是在你的日常工作中你不用過分的擔(dān)心它。在桌面環(huán)境上你將會在100%縮放比例的情況下測試你的站點,但即使用戶放大或者縮小,CSS像素的魔力將會保證你的布局保持相同的比率。

為桌面設(shè)計的網(wǎng)頁在手機(jī)上如何顯示?

先說一下PC web的兩種布局,一般的網(wǎng)頁如果用固定布局都會定義好整個頁面的寬度,常見的寬度是980px,當(dāng)屏幕分辨率的寬度大于980px的時候,如:1024768,頁面就居中,兩邊留白;如果屏幕分辨率小于980px的時候,如:800600,頁面就會出現(xiàn)橫向的滾動條,這應(yīng)該是所有前端開發(fā)人員都不希望出現(xiàn)的,所幸的是目前大多數(shù)顯示器的屏幕分辨率都是1024*768以上的,所以寬度為980px的固定布局是安全又放心的。而如果用流動布局做網(wǎng)頁的話一般要自應(yīng)適不同的分辨率滿屏顯示以讓內(nèi)容區(qū)域達(dá)到最大化,流動布局的例子有很多,如郵箱、博客園等等。

在顯示面積上手機(jī)屏幕相對桌面顯示器要小很多,在幾年前(現(xiàn)在也如此)大部分網(wǎng)站都是為桌面顯示器瀏覽而設(shè)計,很少考慮到適應(yīng)手機(jī)屏幕,所以如果用手機(jī)瀏覽大多網(wǎng)站時會出現(xiàn)問題,比如常見固定寬度的網(wǎng)頁會出現(xiàn)橫向豎向滑動條,當(dāng)然這不算什么大問題;但如果是瀏覽流動布局的網(wǎng)頁那情況會非常糟糕,設(shè)想一個寬度為 30% 的側(cè)邊欄對于 320px 手機(jī)屏幕而言也就 96px,只能容納八個 12px 的漢字,可閱讀性非常差。

接下來說說手機(jī)上打開一個PC web頁面,用手機(jī)打開一個寬度為980的固定布局頁面,頁面會默認(rèn)縮放到剛好滿屏顯示,并不會出現(xiàn)橫向滾動條,這個現(xiàn)象并不讓我感到奇怪,我認(rèn)為這是手機(jī)廠商的一些設(shè)定造成的,但關(guān)鍵是做了什么“手腳”,后來網(wǎng)上查閱了很多資料知道這是因為瀏覽器的兩個viewport:layout viewport & visual viewport

手機(jī)瀏覽器在顯示網(wǎng)頁時,會在設(shè)備屏幕(設(shè)備分辨率)上創(chuàng)建一個980px(css像素)的虛擬窗口,然后使用該虛擬窗口顯示網(wǎng)頁,所以網(wǎng)站會縮小顯示。一般把這個虛擬窗口稱為layout viewport。

說白了其實就是把980px的CSS像素裝進(jìn)了320px(假設(shè)手機(jī)分辨率是320px)的設(shè)備像素下。

layout viewport的默認(rèn)值

在Apple實現(xiàn)viewport后,其他瀏覽器也加入了對viewport meta的支持,但彼此間還是有些差異,差異最大的是layout viewport的表現(xiàn):

Safari iPhone: 980px
Opera: 850px
Android WebKit: 800px
IE: 974px

為什么要使用viewport?

有了 layout viewport 似乎解決手機(jī)瀏覽網(wǎng)頁的難題,但如果遇到專門為手機(jī)優(yōu)化的網(wǎng)頁就又有新的問題:

4

是的,因為 iPhone 的 layout viewport 默認(rèn)為 980px,導(dǎo)致專為其優(yōu)化的 320px 寬的頁面只能以縮放的方式顯示,這時就需要對 viewport 進(jìn)行設(shè)置:

<head>
...
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
...
</head>

這個是最常見的一條 viewport meta 代碼,將 viewport 定義為:寬度為設(shè)備寬度,初始縮放比例為 1 倍,禁止用戶縮放。設(shè)置好后我們的頁面就顯示完美了:

4

一般的桌面端網(wǎng)頁都不會添加 viewport 設(shè)置,用智能手機(jī)查看這些頁面時,是在layout viewport下顯示的。

width=device-width

因為大多數(shù)情況下,<meta name="viewport" content="width=device-width" /> 這個標(biāo)簽對我們來說是最給力的,可以讓我們的頁面里的圖文顯示的是正常的,很大程度上提高了頁面的可讀性。而這一meta標(biāo)簽的功能就是設(shè)置layout viewport為device-width的寬度。但是device-width具體是什么呢?

第一代iphone的時候,分辨率為320480,屏幕尺寸為3.5寸(注意,這個3.5寸說的是屏幕的對角線寬),這時候device-width就是320px,也是手機(jī)的分辨率寬,此時device-width就是設(shè)備寬。但第二代的iphone分辨率提高為了480960,屏幕尺寸為依然為3.5寸,如果device-width還是設(shè)備寬,那么同樣是320px的頁面放480960的手機(jī)屏上,圖文就會變得比較小,又會影響其可讀性。因此iphone的device-width一直維持在320px,ipad一直維持在1024px。這個時候,device-width就不是設(shè)備寬了(也就不是分辨率的寬了),是一個中間層。Android采用的也是這一概念,其device-width值以360居多,但也不乏有像540px和600px這樣的奇葩。在設(shè)置了<meta />標(biāo)簽以后,device-width值可以用window.innerWidth*來獲取device-width值。

獲取device-width

經(jīng)實踐,在手機(jī)端(sony z2)以下兩種方法都可以獲取device-width的值:

1. window.innerWidth/innerHeight
2. document.documentElement.clientWidth/clientHeight

//在sony z2下獲取到的值均為(360,513)

引用自Viewport 不權(quán)威指南
<blockquote>
其實這個屬性值很有意思,字面意應(yīng)該是(layout) viewport 寬度等于設(shè)備寬度,但在實際中不同的瀏覽器都給出了個定值:320px;這個值還是源于 Apple,因為早期 iPhone 的分辨率為 320px × 480px,大量為 iPhone 量身定制的網(wǎng)站都設(shè)置了width=device-width,并且按照寬度 320px 來設(shè)計制作,所以其他瀏覽器加入 viewport 支持時為了兼容性也將 device-width 定義為了 320px。
</blockquote>

initial-scale=1

你肯定不知道

<meta name="viewport" content="initial-scale=1">

<meta name="viewport" content="width=device-width">

這兩句代碼能達(dá)到一樣的效果,也可以把當(dāng)前的的viewport變?yōu)?ideal viewport。

呵呵,傻眼了吧,因為從理論上來講,這句代碼的作用只是不對當(dāng)前的頁面進(jìn)行縮放,也就是頁面本該是多大就是多大。那為什么會有 width=device-width 的效果呢?

要想清楚這件事情,首先你得弄明白這個縮放是相對于什么來縮放的,因為這里的縮放值是1,也就是沒縮放,但卻達(dá)到了 ideal viewport 的效果,所以,那答案就只有一個了,縮放是相對于 ideal viewport來進(jìn)行縮放的,當(dāng)對ideal viewport進(jìn)行100%的縮放,也就是縮放值為1的時候,不就得到了 ideal viewport嗎?事實證明,的確是這樣的。

測試結(jié)果表明 initial-scale=1 也能把當(dāng)前的viewport寬度變成 ideal viewport 的寬度,但這次輪到了windows phone 上的IE 無論是豎屏還是橫屏都把寬度設(shè)為豎屏?xí)rideal viewport的寬度。但這點小瑕疵已經(jīng)無關(guān)緊要了。

但如果width 和 initial-scale=1同時出現(xiàn),并且還出現(xiàn)了沖突呢?比如:

<meta name="viewport" content="width=400, initial-scale=1">

width=400表示把當(dāng)前viewport的寬度設(shè)為400px,initial-scale=1則表示把當(dāng)前viewport的寬度設(shè)為ideal viewport的寬度,那么瀏覽器到底該服從哪個命令呢?是書寫順序在后面的那個嗎?不是。當(dāng)遇到這種情況時,瀏覽器會取它們兩個中較大的那個值。例如,當(dāng)width=400,ideal viewport的寬度為320時,取的是400;當(dāng)width=400, ideal viewport的寬度為480時,取的是ideal viewport的寬度。(ps:在uc9瀏覽器中,當(dāng)initial-scale=1時,無論width屬性的值為多少,此時viewport的寬度永遠(yuǎn)都是ideal viewport的寬度)

initial-scale的默認(rèn)值

好了,現(xiàn)在再來說下initial-scale的默認(rèn)值問題,就是不寫這個屬性的時候,它的默認(rèn)值會是多少呢?很顯然不會是1,因為當(dāng) initial-scale = 1 時,當(dāng)前的layout viewport寬度會被設(shè)為 ideal viewport的寬度,但前面說了,各瀏覽器默認(rèn)的 layout viewport寬度一般都是980啊,1024啊,800啊等等這些個值,沒有一開始就是 ideal viewport的寬度的,所以 initial-scale的默認(rèn)值肯定不是1。安卓設(shè)備上的initial-scale默認(rèn)值好像沒有方法能夠得到,或者就是干脆它就沒有默認(rèn)值,一定要你顯示的寫出來這個東西才會起作用,我們不管它了,這里我們重點說一下iphone和ipad上的initial-scale默認(rèn)值。

根據(jù)測試,我們可以在iphone和ipad上得到一個結(jié)論,就是無論你給layout viewpor設(shè)置的寬度是多少,而又沒有指定初始的縮放值的話,那么iphone和ipad會自動計算initial-scale這個值,以保證當(dāng)前l(fā)ayout viewport的寬度在縮放后就是瀏覽器可視區(qū)域的寬度,也就是說不會出現(xiàn)橫向滾動條。比如說,在iphone上,我們不設(shè)置任何的viewport meta標(biāo)簽,此時layout viewport的寬度為980px,但我們可以看到瀏覽器并沒有出現(xiàn)橫向滾動條,瀏覽器默認(rèn)的把頁面縮小了。根據(jù)上面的公式,當(dāng)前縮放值 = ideal viewport寬度 / visual viewport寬度,我們可以得出:

  當(dāng)前縮放值 = 320 / 980

也就是當(dāng)前的initial-scale默認(rèn)值應(yīng)該是 0.33這樣子。當(dāng)你指定了initial-scale的值后,這個默認(rèn)值就不起作用了。

總之記住這個結(jié)論就行了:在iphone和ipad上,無論你給viewport設(shè)的寬的是多少,如果沒有指定默認(rèn)的縮放值,則iphone和ipad會自動計算這個縮放值,以達(dá)到當(dāng)前頁面不會出現(xiàn)橫向滾動條(或者說viewport的寬度就是屏幕的寬度)的目的。

兼容性

<meta name="viewport" content="width=device-width">

可以看到通過width=device-width,所有瀏覽器都能把當(dāng)前的viewport寬度變成ideal viewport的寬度,但要注意的是,在iphone和ipad上,無論是豎屏還是橫屏,寬度都是豎屏?xí)rideal viewport的寬度。

<meta name="viewport" content="initial-scale=1">

測試結(jié)果表明 initial-scale=1 也能把當(dāng)前的viewport寬度變成 ideal viewport 的寬度,但這次輪到了windows phone 上的IE 無論是豎屏還是橫屏都把寬度設(shè)為豎屏?xí)rideal viewport的寬度。

最后,總結(jié)一下,要把當(dāng)前的viewport寬度設(shè)為ideal viewport的寬度,既可以設(shè)置 width=device-width,也可以設(shè)置 initial-scale=1,但這兩者各有一個小缺陷,就是iphone、ipad以及IE 會橫豎屏不分,通通以豎屏的ideal viewport寬度為準(zhǔn)。所以,最完美的寫法應(yīng)該是,兩者都寫上去,這樣就 initial-scale=1 解決了 iphone、ipad的毛病,width=device-width則解決了IE的毛?。?/p>

<meta name="viewport" content="width=device-width, initial-scale=1">

viewport的自動調(diào)整

其實 viewport 能夠自動調(diào)整的。

  • 當(dāng) width=320 時,橫屏后的 viewport 寬度仍然是 320px ,但可見區(qū)域?qū)挾葹?480px ,因此 viewport 要放大為 320 的 1.5 倍,把 320px 的頁面顯示到 480px 的屏幕上,從而頁面顯示的效果就被放大了。
  • 而當(dāng) width=device-width 時,橫屏后的 viewport 寬度變?yōu)榱?480px ,此時的 viewport 沒有縮放, initial-scale 值仍然為 1 ,所以頁面沒有經(jīng)過縮放。

viewport 自動調(diào)整特性:為了讓頁面適應(yīng) viewport 的顯示區(qū)域進(jìn)行顯示,瀏覽器會自動根據(jù)已設(shè)置值的屬性調(diào)整其它未設(shè)置值的屬性值。

<blockquote>
If you set only some of the properties, then Safari on iOS infers the values of the other properties with the goal of fitting the webpage in the visible area.
</blockquote>

這些可相互影響的屬性值主要包括:width、height、initial-scale。

為什么不制作固定尺寸的頁面,讓瀏覽器自己去縮放

http://segmentfault.com/q/1010000002551392/a-1020000002551691

固定尺寸的頁面:

<meta name="viewport" content="target-densitydpi=device-dpi,width=640,user-scalable=no" />

另外也有這樣的寫法。這是用js的方式。

var phoneScale = parseInt(window.screen.width)/640;
document.write('<meta name="viewport" content="width=640, initial-scale = '+phoneScale+', maximum-scale = '+phoneScale+', maximum-scale = '+phoneScale+', target-densitydpi=device-dpi">');
}

這兩個會讓瀏覽器去縮放。你也知道了,這是縮放。既然是縮放,那么就會失真,這是由于瀏覽器的自身渲染導(dǎo)致的。你發(fā)的網(wǎng)頁,我用nexus4測了一下,雖然不是太過明顯,但里面的灰色線條會有粗細(xì)不一致的問題,也就是說在某些分辨率也會產(chǎn)生幾條1px的直線看起來不一樣粗的情況。這個問題進(jìn)一步的引申,就變成了你無法準(zhǔn)確的在頁面上畫出規(guī)整的直線。

在一些手機(jī)上,如果用了一些下載的字體,甚至?xí)l(fā)虛(字體的問題你可以找資料仔細(xì)看看)。而且一些情況下會有輕微的撕裂和發(fā)糊現(xiàn)象,如果你用了部分CSS3的屬性,發(fā)糊的現(xiàn)象可能會更嚴(yán)重,就是是樓上的說法。還有一個問題就是渲染帶來的卡頓,生產(chǎn)中iPhone表現(xiàn)出了部分頁面滑動不自然。我認(rèn)為這是各個瀏覽器的實現(xiàn)不一樣帶來的渲染兼容問題,不知事實上如何。

我對這種方案的評價是

夠用,但不完美

參考文獻(xiàn)

Viewport 不權(quán)威指南
探索viewport:頁面如何在手機(jī)上顯示
移動前端開發(fā)之viewport的深入理解
一些關(guān)于Viewport與device-width的東西~
Mobile web開發(fā)日記
兩個viewport的故事(第一部分)
兩個viewport的故事(第二部分)
自適應(yīng)網(wǎng)頁設(shè)計(Responsive Web Design)
請教viewport的選擇
網(wǎng)頁寬度自動適應(yīng)手機(jī)屏幕寬度的方法

這只是我參考以上文獻(xiàn)后自己的理解,可能會有一些不正確的地方,歡迎指正。

QQ : 459135899

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容