移動設(shè)備瀏覽器的問題中心在于CSS齐邦,特別是viewport的尺寸。在移動設(shè)備上進(jìn)行網(wǎng)頁的開發(fā)怨绣,首先得搞明白的就是移動設(shè)備上的viewport了探膊,只有明白了viewport的概念以及弄清楚了跟viewport有關(guān)的meta標(biāo)簽的使用,才能更好地讓我們的網(wǎng)頁適配利朵。
幾個(gè)重要的概念####
設(shè)備的pixels和CSS的pixels#####
css中的像素只是一個(gè)抽象的單位律想,在不同的設(shè)備或不同的環(huán)境中,css中的1px所代表的設(shè)備物理像素是不同的绍弟。
物理像素和CSS像素的對應(yīng)關(guān)系:
設(shè)備像素比 = 物理像素 / CSS像素
設(shè)備像素比簡稱 dpr
在網(wǎng)頁開發(fā)中我們不用在意物理像素和dpr這些概念技即,只需知道可以使用的寬度是多少CSS像素就足夠了。
viewport的概念#####
viewport的功能在于控制你網(wǎng)站的最高塊狀(block)容器:<html>元素.
通常樟遣,一個(gè)塊級元素占有起父元素的100%的寬度而叼。所以<body>的寬度就是其父元素<html>的寬度100%。在原理上豹悬,<html>的寬度受viewport所限制葵陵,<html>元素為viewport寬度的100%。viewport不是一個(gè)HTML的概念屿衅,所以不能通過CSS修改它埃难。<html>元素的寬度可以通過document.documentElement.offsetWidth
來獲取。
layout viewport######
當(dāng)通過移動設(shè)備上的瀏覽器瀏覽為PC設(shè)計(jì)的網(wǎng)站時(shí),因?yàn)橐苿釉O(shè)備的屏幕很小涡尘,如果把移動設(shè)備上瀏覽器的可視區(qū)域設(shè)viewport的話忍弛,網(wǎng)站會因?yàn)関iewport太窄而亂作一團(tuán)。為了能使為PC端設(shè)計(jì)的網(wǎng)站能在移動設(shè)備上正常顯示考抄,移動設(shè)備的瀏覽器產(chǎn)商將viewport設(shè)為一個(gè)較大的值细疚,通常是980px。這個(gè)瀏覽器默認(rèn)的viewport叫做layout viewport川梅。這個(gè)layout viewport的寬度可以通過 document.documentElement.clientWidth
來獲取疯兼。
visual viewport#####
visualviewport是當(dāng)前顯示在屏幕上的部分頁面的大小。但是CSS 布局贫途,特別是感性的寬度(percentual widths)通常是按照layoutviewport來定義吧彪,而比visualviewport寬很多。visualviewport的寬度可以通過window.innerWidth來獲取丢早。部分設(shè)備visualviewport的寬度等于layout viewport的寬度姨裸。
根據(jù)上面的描述,顯然visualviewport的寬度和layout viewport的寬度都不適于移動端CSS布局適配怨酝。另外<html>元素的寬度繼承于layout viewport傀缩,如果layout viewport寬度等于屏幕的寬度,那么為移動端設(shè)計(jì)的網(wǎng)站就可以在屏幕中完全顯示农猬。當(dāng)是移動設(shè)備屏幕尺寸眾多赡艰,如何適配所有的設(shè)備?
一種解決方案是根據(jù)瀏覽器窗口的寬度(CSS3中的vw)進(jìn)行CSS布局斤葱,不過這種方案存在瀏覽器兼容問題慷垮。如果你的網(wǎng)站只需要運(yùn)行在現(xiàn)代瀏覽器上,此方案是很好的選擇苦掘。
另一種方案是换帜,頁面所有元素的寬高根據(jù)HTML的根元素<html>的font-size大小來計(jì)算,<html>的font-size根據(jù)屏幕的寬度動態(tài)設(shè)置鹤啡。這就是基于rem的適配方案的核心思想。從下面的圖可以看出rem比vw具有更好的瀏覽器兼容性蹲嚣。所以递瑰,基于rem的適配方案應(yīng)該作為移動界面開發(fā)的首選方案。
rem方案的實(shí)現(xiàn)步驟#####
- 修改layout viewport 的寬度隙畜,使其等于屏幕的寬度抖部,通過添加下面的mete標(biāo)簽就可以做到這點(diǎn)
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
其中width=device-width
用于設(shè)置viewport的寬度等于屏幕的寬度,initial-scale=1.0, maximum-scale=1.0
的作用同width=device-width
一樣议惰,那么慎颗,為什么還要同時(shí)設(shè)置這兩者?因?yàn)楫?dāng)它們單獨(dú)使用時(shí),表現(xiàn)不夠完美俯萎,下面兩張圖展示了單獨(dú)使用時(shí)的瀏覽器兼容性:
為了彌補(bǔ)彼此的缺陷傲宜,所以要同時(shí)設(shè)置。另外夫啊,當(dāng)兩者指定的值不同時(shí)函卒,瀏覽器取其中的最大者。這也是手淘的flexible.js方案動態(tài)添加此<mete>標(biāo)簽時(shí)不添加width=device-width
的原因撇眯。
在手淘的flexible.js方案中initial-scale
和maximum-scale
的縮放值根據(jù)操作系統(tǒng)和屏幕的像素密度(dpr)不同而有所不同报嵌,例如在dpr=2
的iPhone5上縮放比是0.5
(scale=1/dpr
),iPhone5的屏幕寬度是320(CSS的pixels)所以添加<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, user-scalable=0">
后熊榛,viewport的寬度是640(CSS的pixels)
flexible.js的作者為自己挖了一個(gè)坑锚国。設(shè)置特殊的縮放比會帶來后續(xù)的麻煩,如何保證字體在屏幕尺寸相同玄坦,dpr不同的設(shè)備上有相同的表現(xiàn)血筑。舉個(gè)例子:同樣是iPhone5設(shè)備,A設(shè)備的dpr=2
营搅,B設(shè)備的dpr=3
云挟,根據(jù)flexible.js方案,A转质、B設(shè)備的縮放比分別是 0.5和0.3
园欣,為了使A設(shè)備上的font-size=24px
的文字在B設(shè)備上有同樣的表現(xiàn),需要設(shè)置font-size=36px
休蟹。這是因?yàn)锳設(shè)備的scale=0.5
沸枯,A設(shè)備的layout viewpoint的寬度等于640(CSS的pixels),因?yàn)锳設(shè)備的scale=1/3
赂弓,A設(shè)備的layout viewpoint的寬度等于960(CSS的pixels)绑榴,A、B設(shè)備的物理尺寸相同盈魁,要使文字在兩塊屏幕上表現(xiàn)相同翔怎,那么同一個(gè)文字在兩塊屏幕上占的比例也要一樣,所有:A(font-size)/640 = B(font-size)/960
杨耙。為了使采用px
作單位的文字在不同縮放比的屏幕上有一致的表現(xiàn)赤套,需要針對不同的縮放比使用不同大小font-size。采用不同的縮放比是作者挖的坑珊膜,使用不同的font-size是作者為了填自己的坑容握,這兩部就是在畫蛇添腳。從這里已經(jīng)看出车柠,要使同一個(gè)布局在不同的屏幕上表現(xiàn)一至剔氏,關(guān)鍵在保證每個(gè)元素相對viewport的寬度的大小是一致的塑猖。
編寫CSS時(shí)元素的width/height、margin谈跛、padding等使用rem作為單位羊苟,
屬性的數(shù)值 = 設(shè)計(jì)稿上標(biāo)注的數(shù)值 / 設(shè)計(jì)稿的寬度
,這樣就計(jì)算出了設(shè)計(jì)稿上的元素和設(shè)計(jì)稿的比例币旧。在步驟一中我們得出結(jié)論践险,要使同一個(gè)布局在不同的屏幕上表現(xiàn)一至,關(guān)鍵在保證每個(gè)元素相對viewport的寬度的大小是一致的吹菱。接下來要做的就是巍虫,動態(tài)設(shè)置<html>元素的font-size等于layout viewport的寬度。由于我們采用的是rem作為單位鳍刷,這樣變保證了設(shè)計(jì)稿上的布局和不同設(shè)備上呈現(xiàn)的樣式有相同的比例占遥。適配完成。
上面說了flexible.js中有畫蛇添腳的地方输瓜,我自己修改了其中不必要的地方瓦胎,放在了github上H5-flexible。
在寫css時(shí)尤揣,可以使用sass函數(shù)減少px轉(zhuǎn)化為rem的工作量:
@function rem($pixels搔啊, $design_draft_width:?) { @return $pixels / $design_draft_width + rem; }
將?
改為設(shè)計(jì)稿的寬度。