1. 程式人生 > >從淘寶和網易的font-size思考移動端怎樣使用rem?

從淘寶和網易的font-size思考移動端怎樣使用rem?

目前 但是 網易 not 人員 char 舉例 device parseint

最近翻了一下關於移動端的rem的使用,怎樣最方便。在讀到流雲諸葛的一篇關於《從網易與淘寶的font-size思考前端設計稿與工作流》的文章後,來總結一下。

然而根據我以往做移動端web項目的時候,設計稿一般是640或者750的,我一般會在head裏面這樣寫:

<meta name="viewport" content="width=750, user-scalable=no, target-densitydpi=device-dpi"><!-- width取值與頁面定義的寬度一致 -->

做移動端活動的時候結構也一般這樣:

<!DOCTYPE html
> <html> <head> <meta charset="utf-8"> <meta content="yes" name="apple-mobile-web-app-capable"> <!-- ios7.0版本以後,safari上已看不到效果,可以刪除--> <meta content="black" name="apple-mobile-web-app-status-bar-style"> <meta content="telephone=no" name="format-detection"
> <meta content="email=no" name="format-detection"> <title>viewport通用</title> <script type="text/javascript"> var phoneWidth = parseInt(window.screen.width); var phoneScale = phoneWidth / 750; var ua = navigator.userAgent; if (/Android (\d+\.\d+)/.test(ua)) {
var version = parseFloat(RegExp.$1); if (version > 2.3) { document.write(<meta name="viewport" id="vie" content="width=750, minimum-scale = + phoneScale + , maximum-scale = + phoneScale + , target-densitydpi=device-dpi">); } else { document.write(<meta name="viewport" id="vie" content="width=750, target-densitydpi=device-dpi">); } } else { document.write(<meta id="vie" name="viewport" content="width=750, user-scalable=no, target-densitydpi=device-dpi, minimal-ui">); } </script> <link style="text/css" rel="stylesheet" href="home.css"> <script type="text/javascript" src="js/app.js"></script> </head> <body> <!--頁面內容--> </body> </html>

一般的移動頁面通用寫法:

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

也就是下面要想總結的。

在博客園白樹的博文中有一段指出,如果html5要適應各種分辨率的移動設備,應該使用rem這樣的尺寸單位,同時給出了一段針對各個分辨率範圍在html上設置font-size的代碼:

html{font-size:10px}
@media screen and (min-width:321px) and (max-width:375px){html{font-size:11px}}
@media screen and (min-width:376px) and (max-width:414px){html{font-size:12px}}
@media screen and (min-width:415px) and (max-width:639px){html{font-size:15px}}
@media screen and (min-width:640px) and (max-width:719px){html{font-size:20px}}
@media screen and (min-width:720px) and (max-width:749px){html{font-size:22.5px}}
@media screen and (min-width:750px) and (max-width:799px){html{font-size:23.5px}}
@media screen and (min-width:800px){html{font-size:25px}}

在實際項目中,把與元素尺寸有關的css,如width,height,line-height,margin,padding等都以rem作為單位,這樣頁面在不同設備下就能保持一致的網頁布局。舉例來說,網頁有一個.item類,設置了width為3.4rem,該類在不同分辨率下對應的實際寬度如下:

321px <= device-width <= 375px,font-size:11px        --->  .item的width:(11*3.4)px
376px <= device-width <= 414px,font-size:12px        --->  .item的width:(12*3.4)px
415px <= device-width <= 639px,font-size:15px        --->  .item的width:(15*3.4)px
640px <= device-width <= 719px,font-size:20px        --->  .item的width:(20*3.4)px
720px <= device-width <= 749px,font-size:22.5px      --->  .item的width:(22.5*3.4)px
750px <= device-width <= 799px,font-size:23.5px      --->  .item的width:(23.5*3.4)px
800px <= device-width         ,font-size:25px        --->  .item的width:(25*3.4)px

註:說明一下,在流雲諸葛的那篇文章中,上面的font-size為11px的時候,item類的width為34px,為啥不是(11*3.4)px。難道這兒的font-size不是設置的html的font-size?

上面一看,缺點其實是很多的,我覺得要這樣做估計頁面很少,或者是一個啥活動頁面這樣寫兼容也可以。主要缺陷有兩點如下:

  • 根據不同分辨率的屏幕,設置font-size也太多了吧,在實際項目中一般也用不了這麽多。
  • 通過font-size的值,每次去設置margin,width,height,padding等的長度時,都要通過設計搞再計算一下才行。比如比如40px / 11px,你一下說不出結果吧。

有些web app的設計搞確實不復雜,比較簡單,比如拉勾網的布局結構如圖所示:

技術分享

它的頁面有一個特點,就是:

  • 頂部與底部的bar不管分辨率怎麽變,它的高度和位置都不變
  • 中間每條招聘信息不管分辨率怎麽變,招聘公司的圖標等信息都位於條目的左邊,薪資都位於右邊

這種app是一種典型的彈性布局:關鍵元素高寬和位置都不變,只有容器元素在做伸縮變換。對於這類app,記住一個開發原則就好:文字流式,控件彈性,圖片等比縮放。

總之一句話,簡單的設計稿,簡單處理,不必寫得那麽復雜。

網易的做法

第一,視口設置如下:

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

第二,當deviceWidth大於設計稿的橫向分辨率時,html的font-size始終等於橫向分辨率/body元素寬:

如圖所示:

技術分享640*680

技術分享641*680

之所以這麽幹,是因為當deviceWidth大於640時,則物理分辨率大於1280(這就看設備的devicePixelRatio這個值了),應該去訪問pc網站了。事實就是這樣,你從手機訪問網易,看到的是觸屏版的頁面,如果從pad訪問,看到的就是電腦版的頁面。

在dom ready以後,通過以下代碼設置html的font-size:

var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + ‘px‘;

這個6.4怎麽來的,當然是根據設計稿的橫向分辨率/100得來的。

如果設計稿基於iphone6,橫向分辨率為750,body的width為750 / 100 = 7.5rem
如果設計稿基於iphone4/5,橫向分辨率為640,body的width為640 / 100 = 6.4rem

6.4只是舉個例子,如果是750的設計稿,應該除以7.5。

font-size可能需要額外的媒介查詢,並且font-size不能使用rem,如網易的設置:

@media screen and (max-width:321px){
    .m-navlist{font-size:15px}
}

@media screen and (min-width:321px) and (max-width:400px){
    .m-navlist{font-size:16px}
}

@media screen and (min-width:400px){
    .m-navlist{font-size:18px}
}

淘寶的做法

淘寶的效果跟網易的效果其實是類似的,隨著分辨率的變化,頁面元素的尺寸和間距都相應變化,這是因為淘寶的尺寸也是使用了rem的原因。在介紹它的做法之前,先來了解一點關於viewport的知識,通常我們采用如下代碼設置viewport:

<meta name="viewport"   content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

這樣整個網頁在設備內顯示時的頁面寬度就會等於設備邏輯像素大小,也就是device-width。這個device-width的計算公式為:

設備的物理分辨率/(devicePixelRatio * scale),在scale為1的情況下,device-width = 設備的物理分辨率/devicePixelRatio 。

devicePixelRatio稱為設備像素比,每款設備的devicePixelRatio都是已知,並且不變的,目前高清屏,普遍都是2,不過還有更高的,比如2.5, 3 等,魅族note的手機的devicePixelRatio就是3。淘寶觸屏版布局的前提就是viewport的scale根據devicePixelRatio動態設置:

技術分享在devicePixelRatio為2的時候,scale為0.5

技術分享在devicePixelRatio為3的時候,scale為0.3333

這麽做目的當然是為了保證頁面的大小與設計稿保持一致了,比如設計稿如果是750的橫向分辨率,那麽實際頁面的device-width,以iphone6來說,也等於750,這樣的話設計稿上標註的尺寸只要除以某一個值就能夠轉換為rem了。通過js設置viewport的方法如下:

淘寶布局的第二個要點,就是html元素的font-size的計算公式,font-size = deviceWidth / 10:

技術分享

接下來要解決的問題是,元素的尺寸該如何計算,比如說設計稿上某一個元素的寬為150px,換算成rem應該怎麽算呢?這個值等於設計稿標註尺寸/該設計稿對應的html的font-size。拿淘寶來說的,他們用的設計稿是750的,所以html的font-size就是75,如果某個元素時150px的寬,換算成rem就是150 / 75 = 2rem。總結下淘寶的這些做法:

(1)動態設置viewport的scale

var scale = 1 / devicePixelRatio;
document.querySelector(‘meta[name="viewport"]‘).setAttribute(‘content‘,‘initial-scale=‘ + scale + ‘, maximum-scale=‘ + scale + ‘, minimum-scale=‘ + scale + ‘, user-scalable=no‘);

(2)動態計算html的font-size

document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + ‘px‘;

(3)布局的時候,各元素的css尺寸=設計稿標註尺寸/設計稿橫向分辨率/10

(4)font-size可能需要額外的媒介查詢,並且font-size不使用rem,這一點跟網易是一樣的。

最後還有一個情況要說明,跟網易一樣,淘寶也設置了一個臨界點,當設備豎著時橫向物理分辨率大於1080時,html的font-size就不會變化了,原因也是一樣的,分辨率已經可以去訪問電腦版頁面了。

關於這種做法的具體實現,淘寶已經給我們提供了一個開源的解決方案,具體請查看:

https://github.com/amfe/lib-flexible

比較網易與淘寶的做法

共同點:

  • 都能適配所有的手機設備,對於pad,網易與淘寶都會跳轉到pc頁面,不再使用觸屏版的頁面
  • 都需要動態設置html的font-size
  • 布局時各元素的尺寸值都是根據設計稿標註的尺寸計算出來,由於html的font-size是動態調整的,所以能夠做到不同分辨率下頁面布局呈現等比變化
  • 容器元素的font-size都不用rem,需要額外地對font-size做媒介查詢
  • 都能應用於尺寸不同的設計稿,只要按以上總結的方法去用就可以了

不同點:

  • 淘寶的設計稿是基於750的橫向分辨率,網易的設計稿是基於640的橫向分辨率,還要強調的是,雖然設計稿不同,但是最終的結果是一致的,設計稿的尺寸一個公司設計人員的工作標準,每個公司不一樣而已
  • 淘寶還需要動態設置viewport的scale,網易不用
  • 最重要的區別就是:網易的做法,rem值很好計算,淘寶的做法肯定得用計算器才能用好了 。不過要是你使用了less和sass這樣的css處理器,就好辦多了,以淘寶跟less舉例,我們可以這樣編寫less:
//定義一個變量和一個mixin

@baseFontSize: 75;//基於視覺稿橫屏尺寸/100得出的基準font-size
.px2rem(@name, @px){
    @{name}: @px / @baseFontSize * 1rem;
}

//使用示例:

.container {
    .px2rem(height, 240);
}

//less翻譯結果:
.container {
    height: 3.2rem;
}

參考地址:http://www.cnblogs.com/lyzg/p/4877277.html

從淘寶和網易的font-size思考移動端怎樣使用rem?