作者: JeremyWei | 可以轉(zhuǎn)載, 但必須以超鏈接形式標(biāo)明文章原始出處和作者信息及版權(quán)聲明
網(wǎng)址: http://weizhifeng.net/viewports2.html
原文:http://www.quirksmode.org/mobile/viewports2.html
在這個(gè)迷你系列的文章里邊我將會(huì)解釋viewport舞骆,以及許多重要元素的寬度是如何工作的湿滓,比如元素坯临,也包括窗口和屏幕辜御。
這篇文章我們來(lái)聊聊關(guān)于移動(dòng)瀏覽器的內(nèi)容椰弊。如果你對(duì)移動(dòng)開(kāi)發(fā)完全是一個(gè)新手的話蚯窥,我建議你先讀一下第一篇關(guān)于桌面瀏覽器的文章止吁,先在熟悉的環(huán)境中進(jìn)行下熱身佳窑。
移動(dòng)瀏覽器的問(wèn)題
當(dāng)我們比較移動(dòng)瀏覽器和桌面瀏覽器的時(shí)候淋硝,它們最顯而易見(jiàn)的不同就是屏幕尺寸雹熬。為桌面瀏覽器所設(shè)計(jì)的網(wǎng)站在移動(dòng)瀏覽器中顯示的內(nèi)容明顯要少于在桌面瀏覽器中顯示的;不管是對(duì)其進(jìn)行縮放直到文字小得無(wú)法閱讀谣膳,還是在屏幕中以合適的尺寸只顯示站點(diǎn)中的一小部分內(nèi)容竿报。
移動(dòng)設(shè)備的屏幕比桌面屏幕要小得多;想想其最大有400px寬继谚,有時(shí)候會(huì)小很多烈菌。(一些手機(jī)聲稱擁有更大的寬度,但是它在撒謊-或者也可以說(shuō)它給我們提供了沒(méi)用的信息花履。)
平板設(shè)備中的像素中間層會(huì)在桌面環(huán)境和移動(dòng)環(huán)境的缺口之間架起一段橋梁僧界,比如像iPad或者傳說(shuō)中HP基于webOS所研發(fā)的設(shè)備,但是這并沒(méi)有改變根本問(wèn)題臭挽。站點(diǎn)必須也能在移動(dòng)設(shè)備上工作捂襟,所以我們不得不讓它們能在小尺寸的屏幕上正常顯示。
最重要的問(wèn)題在CSS上欢峰,特別是viewport的尺寸葬荷。如果我們照搬桌面環(huán)境的模式涨共,那么我們的CSS就要立馬熄火了(譯者:即顯示混亂)。
讓我們看下之前sidebar為width: 10%的例子宠漩。如果移動(dòng)瀏覽器想要實(shí)現(xiàn)跟桌面瀏覽器一樣的行為举反,它們最多為元素設(shè)置40px的寬度,但是這太窄了扒吁。你的流式布局會(huì)看起來(lái)被擠亂了火鼻。
解決這個(gè)問(wèn)題的一個(gè)方法是為移動(dòng)瀏覽器建立一個(gè)特定的站點(diǎn)饵婆。先拋開(kāi)你是否有必要這么做這個(gè)基本問(wèn)題杭隙,而實(shí)際的情況是只有很少的網(wǎng)站擁有者真正知道要對(duì)移動(dòng)設(shè)備做特殊的處理俩功。
移動(dòng)瀏覽器廠商想給它們的客戶盡可能的提供最好的體驗(yàn)胎撇,這現(xiàn)在指的就是「盡可能的跟桌面一樣」豌鸡。因此耍一些花招是必要的悄晃。
兩個(gè)viewport
viewport太窄了靡菇,以至于不能正常展示你的CSS布局便斥。明顯的解決方案是使viewport變寬一些饶火。無(wú)論如何鹏控,需要把它分成兩部分:visual viewport和layout viewport。
George Cummins在Stack Overflow上對(duì)基本概念給出了最佳解釋:
把layout viewport想像成為一張不會(huì)變更大小或者形狀的大圖》羟蓿現(xiàn)在想像你有一個(gè)小一些的框架当辐,你通過(guò)它來(lái)看這張大圖。(譯者:可以理解為「管中窺豹」)這個(gè)小框架的周圍被不透明的材料所環(huán)繞鲤看,這掩蓋了你所有的視線瀑构,只留這張大圖的一部分給你。你通過(guò)這個(gè)框架所能看到的大圖的部分就是visual viewport刨摩。當(dāng)你保持框架(縮兴律巍)來(lái)看整個(gè)圖片的時(shí)候,你可以不用管大圖澡刹,或者你可以靠近一些(放大)只看局部呻征。你也可以改變框架的方向,但是大圖(layout viewport)的大小和形狀永遠(yuǎn)不會(huì)變罢浇。
也看一下Chris給出的解釋陆赋。
visual viewport是頁(yè)面當(dāng)前顯示在屏幕上的部分。用戶可以通過(guò)滾動(dòng)來(lái)改變他所看到的頁(yè)面的部分嚷闭,或者通過(guò)縮放來(lái)改變visual viewport的大小攒岛。
無(wú)論怎樣,CSS布局胞锰,尤其是百分比寬度灾锯,是以layout viewport做為參照系來(lái)計(jì)算的,它被認(rèn)為要比visual viewport寬嗅榕。
所以元素在初始情況下用的是layout viewport的寬度顺饮,并且你的CSS是在屏幕(譯者注:寬度等于layout viewport的虛擬屏幕)好像明顯比電話屏幕寬(物理屏幕)要寬的假設(shè)基礎(chǔ)上進(jìn)行解釋的吵聪。這使得你站點(diǎn)布局的行為與其在桌面瀏覽器上的一樣。
layout viewport有多寬兼雄?每個(gè)瀏覽器都不一樣吟逝。Safari iPhone為980px,Opera為850px赦肋,Android WebKit為800px块攒,最后IE為974px。
一些瀏覽器有特殊的行為:
Symbian WebKit會(huì)保持layout viewport與visual viewport相等佃乘,是的囱井,這意味著擁有百分比寬度元素的行為可能會(huì)比較奇怪。但是恕稠,如果頁(yè)面由于設(shè)置了絕對(duì)寬度而不能放入visual viewport中,那么瀏覽器會(huì)把layout viewport拉伸到最大850px寬扶欣。
Samsung WebKit (on bada)使layout viewport和最寬的元素一樣寬鹅巍。
在BlackBerry上,layout viewport在100%縮放比例的情況下等于visual viewport料祠。這不會(huì)變骆捧。
縮放
很顯然兩個(gè)viewport都是以CSS像素度量的。但是當(dāng)進(jìn)行縮放(如果你放大髓绽,屏幕上的CSS像素會(huì)變少)的時(shí)候敛苇,visual viewport的尺寸會(huì)發(fā)生變化,layout viewport的尺寸仍然跟之前的一樣顺呕。(如果不這樣枫攀,你的頁(yè)面將會(huì)像百分比寬度被重新計(jì)算一樣而經(jīng)常被重新布局。)
理解layout viewport
為了理解layout viewport的尺寸株茶,我們不得不看一下當(dāng)頁(yè)面被完全縮小后會(huì)發(fā)生什么来涨。許多移動(dòng)瀏覽器會(huì)在初始情況下以完全縮小的模式來(lái)展示任何頁(yè)面。
重點(diǎn)是:瀏覽器已經(jīng)為自己的layout viewport選擇了尺寸启盛,這樣的話它在完全縮小模式的情況下完整的覆蓋了屏幕(并且等于visual viewport)蹦掐。
所以layout viewport的寬度和高度等于在最大限度縮小的模式下屏幕上所能顯示的任何內(nèi)容的尺寸。當(dāng)用戶放大的時(shí)候這些尺寸保持不變僵闯。
layout viewport寬度一直是一樣的卧抗。如果你旋轉(zhuǎn)你的手機(jī),visual viewport會(huì)發(fā)生變化鳖粟,但是瀏覽器通過(guò)輕微的放大來(lái)適配這個(gè)新的朝向社裆,所以layout viewport又和visual viewport一樣寬了。
這對(duì)layout viewport的高度會(huì)有影響向图,現(xiàn)在的高度比肖像模式(豎屏)要小浦马。但是web開(kāi)發(fā)者不在乎高度时呀,只在乎寬度。
度量layout viewport
我們現(xiàn)在有兩個(gè)需要度量的viewport晶默。很幸運(yùn)的是瀏覽器戰(zhàn)爭(zhēng)給我們提供了兩個(gè)屬性對(duì)谨娜。
document.documentElement.clientWidth和-Height包含了layout viewport的尺寸。
document.documentElement.clientWidth/Height
意義:Layout viewport的尺寸
度量單位:CSS像素
完全支持Opera, iPhone, Android, Symbian, Bolt, MicroB, Skyfire, Obigo磺陡。
在Iris中Visual viewport有問(wèn)題
Samsung WebKit在頁(yè)面應(yīng)用了標(biāo)簽的時(shí)候會(huì)返回正確的值趴梢;否則使用元素的尺寸。
Firefox返回以設(shè)備像素為單位的屏幕尺寸币他。
IE返回1024x768坞靶。然而,它把信息存儲(chǔ)在document.body.clientWidth/Height中蝴悉。這和桌面的IE6是一致的彰阴。
NetFront的值只在100%縮放比例的情況下是正確的。
Symbian WebKit 1 (老的S60v3設(shè)備)不支持這些屬性拍冠。
BlackBerry不支持尿这。
朝向會(huì)對(duì)高度產(chǎn)生影響,但對(duì)寬度不會(huì)產(chǎn)生影響庆杜。
度量visual viewport
對(duì)于visual viewport射众,它是通過(guò)window.innerWidth/Height來(lái)進(jìn)行度量的。很明顯當(dāng)用戶縮小或者放大的時(shí)候晃财,度量的尺寸會(huì)發(fā)生變化叨橱,因?yàn)槠聊簧系腃SS像素會(huì)增加或者減少。
window.innerWidth/Height
意義:Visual viewport的尺寸断盛。
度量單位:CSS像素罗洗。
完全支持iPhone,Symbian钢猛,BlackBerry栖博。
問(wèn)題
Opera和Firefox返回以設(shè)備像素為單位的屏幕寬度。
Android厢洞,Bolt仇让,MicroB和NetFront返回以CSS像素為單位的layout viewport尺寸。
不支持IE躺翻,但是它在document.documentElement.offsetWidth/Height中提供visual viewport的尺寸丧叽。
Samsung WebKit返回的是layout viewport或者的尺寸,這取決于頁(yè)面是否應(yīng)用了標(biāo)簽公你。
Iris踊淳,Skyfire,Obigo根本就是扯淡。
不幸的是這是瀏覽器不兼容問(wèn)題中的一部分迂尝;許多瀏覽器仍然不得不增加對(duì)visual viewport度量尺寸的支持脱茉。但是沒(méi)有瀏覽器把這個(gè)度量尺寸存放任何其他的屬性對(duì)中,所以我猜window.innerWidth/Height是標(biāo)準(zhǔn)垄开,盡管它被支持的很糟琴许。
屏幕
像桌面環(huán)境一樣,screen.width/height提供了以設(shè)備像素為單位的屏幕尺寸溉躲。像在桌面環(huán)境上一樣榜田,做為一個(gè)開(kāi)發(fā)者你永遠(yuǎn)不需要這個(gè)信息。你對(duì)屏幕的物理尺寸不感興趣锻梳,而是對(duì)屏幕上當(dāng)前有多少CSS像素感興趣箭券。
screen.width and screen.height
意義:屏幕尺寸
度量單位:設(shè)備像素
完全支持Opera Mini,Android疑枯,Symbian辩块,Iris,F(xiàn)irefox荆永,MicroB废亭,IE,BlackBerry屁魏。
問(wèn)題:Windows Mobile上的Opera Mobile只提供了風(fēng)景模式(橫屏)的尺寸滔以。S60上的Opera Mobile返回的值是正確的捉腥。
Samsung WebKit返回layout viewport或者的尺寸氓拼,這取決于是否在頁(yè)面上應(yīng)用了標(biāo)簽。
iPhone和Obigo只提供了肖像模式(豎屏)的尺寸抵碟。
NetFront只提供風(fēng)景模式(橫屏)的尺寸桃漾。
Bolt,Skyfire依舊在扯淡拟逮。
縮放比例 zoom level
直接讀出縮放比例是不可能的撬统,但是你可以通過(guò)以screen.width除以window.innerWidth來(lái)獲取它的值。當(dāng)然這只有在兩個(gè)屬性都被完美支持的情況下才有用敦迄。
幸運(yùn)的是縮放比例并不太重要恋追。你需要知道的是當(dāng)前屏幕上有多少個(gè)CSS像素。你可以通過(guò)window.innerWidth來(lái)獲取這個(gè)信息罚屋,如果它被正確支持的話苦囱。
滾動(dòng)距離Scrolling offset
你還需知道的是visual viewport當(dāng)前相對(duì)于layout viewport的位置。這是滾動(dòng)距離脾猛,并且就像在桌面一樣撕彤,它被存儲(chǔ)在window.pageX/YOffset之中。
window.pageX/YOffset
意義:滾動(dòng)距離猛拴;與visual viewport相對(duì)于layout viewport的距離一樣羹铅。
度量單位:CSS像素
完全支持iPhone蚀狰,Android,Symbian职员,Iris麻蹋,MicroB,Skyfire廉邑,Obigo哥蔚。
問(wèn)題:Opera,Bolt蛛蒙,F(xiàn)irefox和NetFront一直返回0糙箍。
Samsung WebKit只有當(dāng)被應(yīng)用到頁(yè)面上時(shí)候才返回正確的值。
不支持IE牵祟,BlackBerry深夯。IE把值存在document.documentElement.scrollLeft/Top之中。
\ 元素
就像在桌面上一樣诺苹,document.documentElement.offsetWidth/Height提供了以CSS像素為單位的元素的整個(gè)尺寸咕晋。
document.documentElement.offsetWidth/Height
意義:元素的整體尺寸。
度量單位:CSS像素收奔。
完全支持Opera掌呜,iPhone,Android坪哄,Symbian质蕉,Samsung,Iris翩肌,Bolt模暗,F(xiàn)irefox,MicroB念祭,Skyfire兑宇,BlackBerry,Obigo粱坤。
問(wèn)題:NetFront的值只在100%縮放比例的情況下才正確隶糕。
IE使用這個(gè)屬性對(duì)來(lái)存儲(chǔ)visual viewport的尺寸。在IE中站玄,去document.body.clientWidth/Height中獲取正確的值枚驻。
媒體查詢Media queries
媒體查詢和其在桌面環(huán)境上的工作方式一樣。width/height使用layout viewport做為參照物蜒什,并且以CSS像素進(jìn)行度量测秸,device-width/height使用設(shè)備屏幕,并且以設(shè)備像素進(jìn)行度量。
換句話說(shuō)霎冯,width/height是document.documentElement.clientWidth/Height值的鏡像铃拇,同時(shí)device-width/height是screen.width/height值的鏡像。(它們?cè)谒袨g覽器中實(shí)際上就是這么做的沈撞,即使這個(gè)鏡像的值不正確慷荔。)
媒體查詢
意義:度量元素的寬度(CSS像素)或者設(shè)備寬度(設(shè)備像素)。
完全支持Opera缠俺,iPhone显晶,Android,Symbian壹士,Samsung磷雇,Iris,Bolt躏救,F(xiàn)irefox唯笙,MicroB。
不支持Skyfire盒使,IE崩掘,BlackBerry,NetFront少办,Obigo苞慢。
注意我在這里測(cè)試的是瀏覽器是否能從正確的「屬性對(duì)」獲取它們的數(shù)據(jù)。這些屬性對(duì)是否提供正確的信息不是這個(gè)測(cè)試的一部分英妓。
現(xiàn)在哪個(gè)度量的尺寸對(duì)web開(kāi)發(fā)者更有用挽放?我的觀點(diǎn)是,不知道鞋拟。
我開(kāi)始認(rèn)為device-width是最重要的那一個(gè)骂维,因?yàn)樗o我們提供了關(guān)于我們可能會(huì)使用的設(shè)備的一些信息惹资。比如贺纲,你可以根據(jù)設(shè)備的寬度來(lái)更改你的布局的寬度。不過(guò)褪测,你也可以使用來(lái)做這件事情猴誊;使用device-width媒體查詢并不是絕對(duì)必要的。
那么width究竟是不是更重要的媒體查詢呢侮措?可能是懈叹;它提供了某些線索,這些線索是關(guān)于瀏覽器廠商認(rèn)為在這個(gè)設(shè)備上網(wǎng)站應(yīng)該有的正確寬度分扎。但是這有些模糊不清澄成,并且width媒體查詢實(shí)際上不提供任何其他信息。
所以我不做選擇。目前我認(rèn)為媒體查詢?cè)诜直婺闶欠裨谑褂米烂骐娔X墨状,平板卫漫,或者移動(dòng)設(shè)備方面很重要,但是對(duì)于區(qū)分各種平板或者移動(dòng)設(shè)備并沒(méi)有什么用肾砂。
或者還有其他用處列赎。
事件坐標(biāo)
這里的事件坐標(biāo)與其在桌面環(huán)境上的工作方式差不多。不幸的是镐确,在十二個(gè)測(cè)試過(guò)的瀏覽器中只有Symbian WebKit和Iris這兩個(gè)瀏覽器能獲取到三個(gè)完全正確的值包吝。其他所有瀏覽器都或多或少有些嚴(yán)重的問(wèn)題。
pageX/Y仍然是相對(duì)于頁(yè)面源葫,以CSS像素為單位诗越,并且它是目前為止三個(gè)屬性對(duì)中最有用的,就像它在桌面環(huán)境上的那樣息堂。
Event coordinates
意義:見(jiàn)正文
度量單位:見(jiàn)正文
完全支持Symbian掺喻,Iris
問(wèn)題:Opera Mobile在三個(gè)屬性對(duì)中提供的都是pageX/Y的值,但是當(dāng)你滾動(dòng)一段距離后就出問(wèn)題了储矩。
在iPhone感耙,F(xiàn)irefox和BlackBerry上clientX/Y等于pageX/Y。
在Android和MicroB上screenX/Y等于clientX/Y(換句話說(shuō)持隧,也就是以CSS像素為單位)即硼。
在Firefox上screenX/Y是錯(cuò)的。
IE屡拨,BlackBerry和Obigo不支持pageX/Y只酥。
在NetFront上三個(gè)屬性對(duì)的值都等于screenX/Y。
在Obigo上clientX/Y等于screenX/Y呀狼。
Samsung WebKit一直返回pageX/Y裂允。
沒(méi)有在Opera Mini,Bolt哥艇,Skyfire上測(cè)試過(guò)绝编。
clientX/Y是相對(duì)于visual viewport來(lái)計(jì)算,以CSS像素為單位的貌踏。這有道理的十饥,即使我還不能完全指出這么做的好處。
screenX/Y是相對(duì)于屏幕來(lái)計(jì)算祖乳,以設(shè)備像素為單位逗堵。當(dāng)然,這和clientX/Y用的參照系是一樣的眷昆,并且設(shè)備像素在這沒(méi)有用處蜒秤。所以我們不需要擔(dān)心screenX/Y汁咏;跟在桌面環(huán)境上一樣沒(méi)有用處。
viewport meta標(biāo)簽
Meta viewport
意義:設(shè)置layout viewport的寬度作媚。
度量單位:CSS像素梆暖。
完全支持Opera Mobile,iPhone掂骏,Android轰驳,Iris,IE弟灼,BlackBerry级解,Obigo。
不支持Opera Mini田绑,Symbian勤哗,Bolt,F(xiàn)irefox掩驱,MicroB芒划,NetFront。
問(wèn)題:Skyfire不能處理我的測(cè)試頁(yè)面欧穴。
如果在Samsung WebKit中對(duì)頁(yè)面應(yīng)用民逼,一些其他屬性的意義會(huì)發(fā)生變化。
Opera Mobile涮帘,iPhone拼苍,Samsung和BlackBerry不允許用戶進(jìn)行縮小。
最后调缨,讓我們討論一下疮鲫;起初它是蘋(píng)果做的一個(gè)擴(kuò)展,但是與此同時(shí)被更多的瀏覽器所借鑒弦叶。它的意思是調(diào)整layout viewport的大小俊犯。為了理解為什么這么做是必要的,讓我們后退一步伤哺。
假設(shè)你創(chuàng)建了一個(gè)簡(jiǎn)單的頁(yè)面燕侠,并且沒(méi)有給你的元素設(shè)置「寬度」。那么現(xiàn)在它們會(huì)被拉伸來(lái)填滿layout viewport寬度的100%默责。大部分瀏覽器會(huì)進(jìn)行縮放從而在屏幕上展示整個(gè)layout viewport贬循,產(chǎn)生下面這樣的效果:
所有用戶將會(huì)立刻進(jìn)行放大操作咸包,這個(gè)是工作的桃序,但是大部分瀏覽器完好無(wú)缺的保持元素的寬度,這使得文字很難閱讀烂瘫。
(值得注意的例外是Android WebKit媒熊,它實(shí)際上會(huì)減小包含文字的元素的大小奇适,所以文字就能適配屏幕。這簡(jiǎn)直太有才了芦鳍,我覺(jué)得所有其他瀏覽器應(yīng)該借鑒這個(gè)行為嚷往。我過(guò)陣子將會(huì)完整的寫(xiě)一下這個(gè)議題。)
現(xiàn)在你應(yīng)該嘗試設(shè)置html {width: 320px}∧疲現(xiàn)在元素收縮了皮仁,并且其他元素現(xiàn)在使用的是320px的100%。這在用戶進(jìn)行放大操作的時(shí)候有用菲宴,但是在初始狀態(tài)是沒(méi)用的贷祈,當(dāng)用戶面對(duì)一個(gè)縮小了的頁(yè)面這幾乎不包含任何內(nèi)容。
為了繞開(kāi)這個(gè)問(wèn)題蘋(píng)果發(fā)明了viewport meta標(biāo)簽喝峦。當(dāng)你設(shè)置的時(shí)候势誊,你就設(shè)置了layout viewport的寬度為320px。現(xiàn)在頁(yè)面的初始狀態(tài)也是正確的谣蠢。
你可以把layout viewport的寬度設(shè)置為任何你想要的尺寸粟耻,包括device-width。device-width會(huì)把screen.width(以設(shè)備像素為單位)做為其值眉踱,并相應(yīng)的重置layout viewport的尺寸挤忙。
但這里有一個(gè)隱情。有時(shí)候正規(guī)的screen.width不那么明了谈喳,因?yàn)橄袼氐臄?shù)量太大了饭玲。比如,Nexus One的正規(guī)寬度是480px叁执,但是Google的工程師們覺(jué)得當(dāng)使用device-width的時(shí)候茄厘,layout viewport的寬度為480px,這有些太大了谈宛。他們把寬度縮小為三分之二次哈,所以device-width會(huì)返回給你一個(gè)320px的寬度,就像在iPhone上一樣吆录。
如果窑滞,像傳聞那樣,新的iPhone將會(huì)炫耀一個(gè)更大的像素?cái)?shù)量(并不意味著一個(gè)更大的屏幕)恢筝,如果蘋(píng)果借鑒了這個(gè)行為我將不會(huì)感到驚訝哀卫。也許最終device-width就意味著320px。
相關(guān)研究
一些相關(guān)的主題不得不需要進(jìn)行更深一步的研究:
position: fixed撬槽。一個(gè)固定的元素此改,就像我們知道的那樣,是相對(duì)于viewport來(lái)進(jìn)行定位的侄柔。但是相對(duì)于哪個(gè)viewport共啃?我正在同時(shí)做這個(gè)研究占调。
其他媒體查詢:dpi,orientation移剪,aspect-ratio究珊。尤其是dpi,那是一個(gè)災(zāi)難地區(qū)纵苛,不僅僅是因?yàn)樗袨g覽器都返回96dpi剿涮,通常都是錯(cuò)的,也是因?yàn)槲彝耆淮_定對(duì)于web開(kāi)發(fā)者來(lái)說(shuō)哪個(gè)值是他們最感興趣的攻人。
當(dāng)一個(gè)元素比layout viewport/HTML元素寬的時(shí)候會(huì)發(fā)生什么幔虏?比如我把一個(gè)擁有width: 1500px屬性的元素插入到我的測(cè)試頁(yè)面中的一個(gè)?這個(gè)元素將會(huì)從HTML元素中伸出來(lái)(overflow: visible)贝椿,但這意味著實(shí)際的viewport可以變得比layout viewport要寬想括。除了這個(gè)以外,舊Android(Nexus One)還會(huì)當(dāng)這個(gè)發(fā)生的時(shí)候放大HTML元素烙博。這是個(gè)好主意嗎瑟蜈?
(完)