坑爹的viewport

[size=medium]

最近我做了一點兒針對手機的Web開發和相關研究。按說,Web自設計之初,就已經考慮了設備無關性。然而,[b]現實總是不盡如人意[/b]。

我們知道大多數網頁都是針對桌面顯示器開發和測試的,但是手機屏幕通常要比桌面顯示器小很多,比如iPhone也就是320px。那麼那些網頁在手機上如何瀏覽呢?

一種是把網頁縮放到很小,你可以看到整個網頁但是看不清字了;或者只看網頁的一個局部,然後上下左右移動來看其他部分。現在的手機瀏覽器把兩種模式結合使用。[/size][size=small](或許還有第三種——分析網頁,將其中內容抽取出來,重組,然後呈現,不過這裏不討論這種方式。)[/size][size=medium]

如果僅僅是出現橫向滾動條,那問題倒不是很大。對於那些採用固定佈局的“像素級精確設計”確實就是如此。但是使用自適應佈局的網頁就有問題了。比如一個三欄佈局,其中一個邊欄可能只有20%寬度,320px的屏幕上只有60多像素,只能放5個漢字,排版不美觀不要說,如果裏面有一些圖片,很可能圖片的寬度都超過60像素,造成overflow,從而破壞了佈局。另一種常見佈局方式是採用固定大小的邊欄,例如240px寬,而主體部分則自適應寬度。然而對於320px的屏幕來說,本來是次要的邊欄佔據了3/4空間,主要部分卻只有1/4空間,另外也極有可能因爲內容包含圖片等造成overflow。

說到這裏,那些喜歡固定佈局的人(比如那些熱衷於960px grid排版的同志們——哦,最近[url=http://ued.taobao.com/blog/2011/01/11/dev-share-for-taobao-new-homepage/]淘寶升級成1000並放棄了柵格[/url]!不過那仍然是固定佈局)可能要樂了,你們倡導了半天流式佈局,結果在mobile設備上表現反而很糟糕,真是費力不討好。

真正掌握CSS的同志(是的,珍稀動物!)肯定會反駁。上面這些問題其實都[b]很容易[/b]解決。比如設定min-width。還有,適應不同屏幕大小的“正確”的方案,應該用media query。

問題是,大多數網頁沒有這麼做!或者說不是按照“正確”的方式寫的!未必是網頁作者不懂CSS,而只是他們壓根沒費心考慮過手機大小的屏幕(毫不慚愧的說,本人也是其中一份子)。你可以試着把桌面瀏覽器收縮成320px寬(或者可以試着zoom in到300%),可以看到不少網頁會發生嚴重的佈局錯亂,至少也是瀏覽體驗上的大幅下降。爲了迎合這些網頁,手機瀏覽器廠商發明了[url=http://www.quirksmode.org/mobile/viewports2.html]兩個viewport[/url]。

簡單來說,就是手機瀏覽器把自己冒充爲擁有一個更寬的屏幕,這樣頁面的佈局就能跟桌面瀏覽器一樣了。不同瀏覽器冒充的數值不一樣:iPhone是神奇的980——960它表弟;Android是保守的800——冒充一個800*600的顯示器;而Windows Phone 7則是1024——冒充一個1024*768的顯示器(充分體現微軟的庸俗特質)。

原本佈局就是按照viewport(桌面上的瀏覽器窗口)大小來進行的,現在決定佈局的viewport和窗口[b]分裂[/b]了,產生了兩個viewport。

兩個viewport其實並不新鮮。就像前面說的,所有做固定佈局的同學其實都在不自覺使用兩個viewport——固定佈局,其實相當於人爲設定了佈局viewport。

使用獨立的佈局viewport還有一個好處,那就是縮放變得很簡單,不用引起relayout。

在瀏覽器的歷史上,主要有兩種不同的縮放方式,一種是以IE6爲代表的縮放(文字大小),實質是改變root元素的字體大小。另一種是像素縮放,實質是改變CSS pixel的大小(即1個css像素不再對應1個物理像素),或者說改變了瀏覽器的內部DPI。(Firefox還支持真正的字體縮放,與改變root元素的字體大小不同,它會縮放所有元素的font-size最終使用的值(used value),因此不僅對於以em設定的字體大小有效,對於以px和pt等所有單位設定的字體大小都有效。)

在桌面瀏覽器上,因爲縮放時viewport的物理大小是固定的,如果進行像素縮放,實際就意味着viewport以CSS pixel計算的寬度和高度會隨之改變,比如若放大到200%,CSS寬高就會縮小到原來的50%。而這必然引起relayout。

相反,在mobile瀏覽器上,像素縮放時,佈局viewport的物理大小可隨之縮放,因此其CSS寬高值是不變的,就不必引起relayout。這不僅避免了relayout的大量計算,也更符合移動設備上的用戶體驗(考慮一下你如何縮放地圖就明白了)。

雖然兩個viewport能比較好的解決在手機上瀏覽過往網頁的問題,然而,這畢竟是一個向後看的方案,體驗畢竟是受限的。想象在320寬的窗口裏看960固定佈局的網頁,不可避免的要時常縮放和使用橫向滾動條。在觸摸屏上我們可以用手勢來控制,會方便一點,但是仍然很麻煩。所以絕大多數移動Web開發者最終還是選擇針對小屏幕(重新)進行設計。

不過一個顯然的問題是,如果我的網頁已經考慮了小屏幕,甚至就是專門爲手機設計的,那麼我其實不需要兩個viewport(也不需要縮放),這時候怎麼辦?更一般的問題是,如果我設計的網頁不是針對960或者800或者1024的呢(至少你選了960,就排除了800和1024;你選了800,就排除了960和1024;你選了1024,就排除了800和960……)?

於是Apple發明了viewport的meta標籤,例如:
<meta name="[b]viewport[/b]" content="[b]width[/b]=320, [b]initial-scale[/b]=1.0, [b]minimum-scale[/b]=1.0, [b]maximum-scale[/b]=1.0">

其中width表示網頁的佈局layout寬度。initial-scale表示初始時的縮放比例,minimum-scale和maximum-scale分別表示最小和最大縮放比例。這樣,上面這個meta就表示佈局寬度320像素,初始縮放爲1倍(即不縮放),且禁止用戶縮放(因爲最大最小縮放都爲1倍)——一個專爲iPhone優化的網頁通常就會用這樣的設置。

如果你是針對960設計的,那麼可以用這樣一個meta:
<meta name="viewport" content="width=960, initial-scale=0.33">
這表示佈局寬度爲960像素,初始縮放爲0.33,也就是,會縮小到大約1/3,這樣正好可以在320像素的寬度裏看到整個網頁。你也可以不設initial-scale,因爲手機瀏覽器大多默認會初始縮放到可容納整個網頁寬度。

嗯,看上去不錯吧。

可是,說到底,手機瀏覽器的這種設計,實際上揭示了一個難堪的真相——你們這些網頁仔,其實從來沒真正做好過屏幕適應。因爲一個能自動完美適應不同屏幕大小的“正確”方案,width的取值就不應該是一個固定數字。幸好,safari的工程師在發明viewport時還是給我們留了點面子,width的取值除了像320或960這樣的數字,也可以是關鍵字device-width(其實我認爲更合適的詞是auto),表示採用設備寬度。

然而,歷史總是杯具的重複自己。微軟就又(嗯,我爲什麼要說“又”呢?)貢獻了這樣一個例子:Window Phone 7的設備寬度通常至少是480,那麼按理說,如果viewport中設置了width=device-width,layout寬度應該是480像素,可是[url=http://blogs.msdn.com/b/iemobile/archive/2010/11/22/the-ie-mobile-viewport-on-windows-phone-7.aspx]IE mobile會將viewport設爲320[/url]!這是神馬原因呢?

原來據說微軟收集的數據表明,有大量站點使用了device-width,但是其實只爲320像素寬(也就是iPhone的寬度)優化——比如直接用一個固定寬度320px的<div>將內容wrap起來!我勒個去,諸位移動Web開發者,你們有木有這麼幹?有木有!

那後面的故事就不用說了。微軟當然是做出了一個“正確”的選擇。

另外需要注意的是,width只是設置layout寬度,還要乘上縮放比例,才能得到最終的顯示寬度。那麼對於480像素的屏幕來說,若device-width“被320”,那initial-scale應該是1.5才能佔滿整個屏幕寬度。可是如前所述,針對性優化的網頁會把initial-scale設成1.0!

對此微軟是如何處理的呢?文檔語焉不詳,而其模擬器要在Windows 7上才能運行,所以我也暫時沒有進行實測,不過據我推測,其initial-scale應該仍舊會保持1.0,也就是這1.5會變成額外的縮放因子。實際上其他移動瀏覽器已經這樣做了,比如Fennec(Firefox的移動版)就是如此。Android和iPhone 4也都有類似的設計,爲什麼會這樣?這樣會不會產生新問題?留待下一篇博客再討論。


[/size]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章