移動端適配方案,說多也很多。可以使用百分比布局,但百分比與em都是基於父元素進行計算的,在實際應用中不是很方便。使用rem不僅可以設置字體大小,塊大小也可以設置。而且可以良好的適配各種終端,所以這方案很受歡迎。
rem定義及瀏覽器支持情況
rem(font size of the root element)是指相對於根元素的字體大小的單位。簡單的說它就是一個相對單位。看到rem一定會想起em單位,em(font size of the element)是指相對於父元素的字體大小的單位。它們之間其實很相似,只不過一個計算的規則是依賴根元素一個是依賴父元素計算。可以先看看rem的瀏覽器支持情況:
- Chrome 31-34 & Chrome-based Android versions (like 4.4) have a font size bug that occurs when the root element has a percentage-based size.
- Reportedly does not work on Android 4.3 browser for Samsung Note II or the Samsung Galaxy Tab 2 on Android 4.2.
- Borders sized in "rem" disappear when the page is zoomed out in Chrome.
- IE 9, 10 and 11 do not support rem units when used in the "line-height" property when used on :before and :after pseudo elements (https://connect.microsoft.com/IE/feedback/details/776744).
- Causes content display and scrolling issues on iPhone 4 which typically has Safari 5.1.
可以看到移動端基本支持:
ios:6.1系統以上支持;
android:2.1系統以上都支持;
桌面端IE支持情況不樂觀。
用法:
現代瀏覽器,IE9+,FireFox,Safari,Chrome,Opera,默認字體是16px,設置下根元素的字體大小為16px:
html { font-size:16px; }
,然后,如果希望某段文字的字體大小是12px,需要設置:
p { font-size: 0.75rem; //12÷16=0.75(rem) }
塊大小的設置是類似的,所以整個布局的關鍵就是設置根元素的字體大小了。設置好根元素字體大小值,布局就可以做到自適應了。
塊大小的設置,來個例子:
設置根元素字體大小為37.5px,在iphone6里面需要一個寬100px的塊,就是這樣了:
<!DOCTYPE html> <html> <meta charset="utf-8"></meta> <head> <title>vertical-align</title> <style type="text/css"> html{ font-size:37.5px; } #contentBox{ width:2.667rem; height:2.667rem; background:pink; } </style> </head> <body> <div id="contentBox"> </div> </body> </html>
如果在iphone5下想得到一個100px的塊,需要設置基准值(即根元素字號)為32px。
下面專門談談rem的基准值設置。
rem基准值設置
想要rem適配不同尺寸的設備,就需要針對不同設備設置合適的基准值,如上例所示。
問題來了,基准值設置成多少合適?
一般拿到的設計稿是375px(2倍稿)*2的,也就是iphone6的大小。那么對於iphone6來說,基准值可以設置為37.5px。即設備寬度/10。這里做了一個除以10的計算,是因為不希望font-size值太大。這樣使用rem時值也不會太大了。
如果是iphone5,基准值就是32px。
問題又來了,如何根據設備尺寸來設置基准值?
有兩個方法,通過css media query 和js添加基准值:
css media query:
@media (min-device-width : 375px) and (max-device-width : 667px) and (-webkit-min-device-pixel-ratio : 2){ html{font-size: 37.5px;} }
用media query來實現難覆蓋到所有設備:
html { font-size : 20px; } @media only screen and (min-width: 401px){ html { font-size: 25px !important; } } @media only screen and (min-width: 428px){ html { font-size: 26.75px !important; } } @media only screen and (min-width: 481px){ html { font-size: 30px !important; } } @media only screen and (min-width: 569px){ html { font-size: 35px !important; } } @media only screen and (min-width: 641px){ html { font-size: 40px !important; } }
而通過js來設置,可以實現覆蓋所有設備:
js來設置:
document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';
關於方案的利弊,其實上面的例子里面可以看出,rem為整數的時候,基准值為32px,36px這樣的整數,換成px也是整數。但rem帶有小數,比如1.75rem,在32px的基准只下計算得56px。那再看看其他機型的換算值:
代表機型 | 瀏覽器寬 | 對應尺寸 |
---|---|---|
iPhone 4/4s/5/5s | 320px | 56px |
Samsung Note 3, Nexus 5… | 360px | 63px |
iPhone 6 | 375px | 65.625px |
Google Nexus 6 | 412px | 72.1px |
iPhone 6 Plus | 414px | 72.45px |
可以看出,有些機型里面是有小數像素值的。小數像素可能會帶來一定的誤差,設計的同事像素眼很容易覺察到的。
在可以接受的情況下允許這些誤差存在。在安卓機子上較多出現這類情況。
下面可以具體看下小數像素在瀏覽器里面的顯示情況:
設置兩組塊,第一組是1.75rem*1.75rem的,第二組是1.85rem*1.85rem的,具體代碼如下:
.block{ display:inline-block; width:1.75rem; height:1.75rem; background:rgba(0,0,255, .5); } .block:nth-of-type(2n){ background:rgba(255,0,0, .5); } .group2 .block{ widrh:1.85rem; height:1.85rem; }
效果圖是
看下第一組塊,在iPhone6下,每個塊的尺寸應該是:1.75*37.5=65.625px;
但實際情況:
是的,瀏覽器會顯示為65px或66px,而且沒有規律的來顯示。
這看起來有點不可思議,按道理來說,瀏覽器似乎應該全部舍棄小數65px,或者保留到66px,可事實卻不是這樣的。
到這里,可以假設:瀏覽器所做的渲染處理只是作用在元素的渲染尺寸上,但他們的真實尺寸仍是原始尺寸大小。
舉個實際的例子來說,就是一個元素的尺寸是0.625px,他的渲染尺寸是1px,剩下的0.375px由臨近元素填充;同理,如果一個元素是0.375px,其渲染尺寸是0px,但是會占有臨近元素0.375px的空間。
然后帶着這個假設分析下上面的例子:
第一個塊的寬度為 65.625px,根據四舍五入的原則其最終渲染尺寸為 66px,空出的 0.375px 由第二個塊補上;
第二個塊向左補進 0.375px,相當於減少了 0.375px,余下 65.25px,根據四舍五入的原則其最終渲染尺寸為 65px,多出的 0.25px 會占用第三個色的空間;
第三個塊被占用了 0.25px,相當於增加了 0.25px,等於 65.875px,根據四舍五入的原則其最終渲染尺寸為 66px,空出的 0.125px 由第四個塊補上;
第四個塊向左補進 0.125px,相當於減少了 0.125px,余下 65.5px,根據四舍五入的原則其最終渲染尺寸為 66px,空出的 0.5px 由第五個塊補上;
第五個塊向左補進 0.5px,相當於減少了 0.5px,余下 65.125px,根據四舍五入的原則其最終渲染尺寸為 65px,多出 0.125px;
這與瀏覽器的輸出結果是一致的,印證了猜想。
更具體的瀏覽器處理可以看http://trac.webkit.org/wiki/LayoutUnit
其他適配方案
也可以采用固定布局:
1.在viewport meta標簽上設置width=320,頁面的各個元素也采用px作為單位。通過用JS動態修改標簽的initial-scale使得頁面等比縮放,從而剛好占滿整個屏幕。
<meta name="viewport" content="width=320,user-scalable=no">
2.rem也可以使用自己設置viewport和content的方法來適配,以方便計算和設置值:
例如:
meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');
其中dpr通過window.devicePixelRatio獲取,iphone6的值是2.
對於2倍稿,可以直接設置基准值為2倍,這樣就不用設計稿的值除以2了。
iphone6適配的設計稿750px,基准值設置為75px就可以了。
修改了縮放倍數之后,1px邊線的問題也同時解決了。
代碼:
<!DOCTYPE html> <html> <meta charset="utf-8"></meta> <meta name="viewport" content="" id="viewMeta"> <head> <title>vertical-align</title> <style type="text/css"> html{ font-size:75px; } #contentBox{ width:2.667rem; height:2.667rem; background:pink; border:1px solid #000; } </style> </head> <body> <div id="contentBox"> </div> </body> <script type="text/javascript"> var meta = document.getElementById('viewMeta'); var dpr = window.devicePixelRatio; meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no'); </script> </html>
圖圖:
參考: