1. 程式人生 > >從網易與淘寶的font-size思考前端設計稿與工作流

從網易與淘寶的font-size思考前端設計稿與工作流

目的 矢量 標註 工作流程 查詢 scrip ipad tel 意義

從博主學習前端一路過來的經歷了解到,前端移動開發是大部分從PC端轉戰移動端的小夥伴都非常頭疼的一個問題,這邊博主就根據一篇自己看過的移動開發文章來剖析一下網易和淘寶的rem解決方案,希望能夠幫助到一些從PC端轉戰web移動開發的小夥伴,因為是第一次寫博文,寫得不好的地方也希望大家多多包涵啦(*^__^*) 嘻嘻……(ps:文章有點長,如果你現在時間緊迫,那可以先收藏,等到有時間了再回頭慢慢品嘗喔)

首先我們一起看看這篇打通博主web移動開發任督二脈的武功秘籍吧(以下內容到分割線前是引用前端大牛的文章,方便大家理解博主內容):

1. 簡單問題簡單解決

我覺得有些web app並一定很復雜,比如拉勾網,你看看它的頁面在iphone4,iphone6,ipad下的樣子就知道了:

技術分享圖片技術分享圖片

技術分享圖片

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

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

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

技術分享圖片

這個規則是一套基本的適配規則,對於這種簡單app來說已經足夠,同時它也是後面要說的rem布局的基礎。另外對於拉勾這種app可能需要額外媒介查詢對布局進行調整的就是小屏幕設備。舉例來說,因為現在很多設計稿是根據iphone6的尺寸來的,而iphon6設備寬的邏輯的像素是375px,而iphone4的邏輯像素是320個像素,所以如果你根據設計稿做出來的東西,在iphone4裏面可能顯示不下,比如說拉鉤網底部那個下載框,你對比看下就知道了,這是4:

技術分享圖片

這是6:

技術分享圖片

via6下面兩邊的間距比4多很多,說明拉勾對4肯定是做過適配的,從代碼也可以證實這一點:原文來自:http://caibaojian.com/mobile-responsive-example.html

技術分享圖片

不過如果你拿到的是根據4的設計稿,那就沒有問題,比4分辨率大的設備肯定能顯示根據4的尺寸做出來的東西。

還有一點,這種情況css尺寸單位用px就好,不要用rem,避免增加復雜度。

2. 網易的做法

先來看看網易在不同分辨率下,呈現的效果:

技術分享圖片技術分享圖片

技術分享圖片技術分享圖片

從上面幾張圖可以看出,隨著分辨率的增大,頁面的效果會發生明顯變化,主要體現在各個元素的寬高與間距。375*680的比320*680的導航欄明顯要高。能夠達到這種效果的根本原因就是因為網易頁面裏除了font-size之外的其它css尺寸都使用了rem作為單位,比如你看導航欄的高度設置代碼:

技術分享圖片

可是在本文第1部分提到,使用rem布局結合在html上根據不同分辨率設置不同font-size有很多不好解決的麻煩,網易是如何解決的呢?最根本的原因在於,網易頁面上html的font-size不是預先通過媒介查詢在css裏定義好的,而是通過JS計算出來的,所以當分辨率發生變化時,html的font-size就會變,不過這得在你調整分辨率後,刷新頁面才能看得到效果。你看代碼就知道為啥font-size是直接寫到html的style上面的了(js設置的原因):

技術分享圖片

它是根據什麽計算的,這就跟設計稿有關了,拿網易來說,它的設計稿應該是基於iphone4或者iphone5來的,所以它的設計稿豎直放時的橫向分辨率為640px,為了計算方便,取一個100px的font-size為參照,那麽body元素的寬度就可以設置為width: 6.4rem,於是html的font-size=deviceWidth / 6.4。這個deviceWidth就是viewport設置中的那個deviceWidth。根據這個計算規則,可得出本部分開始的四張截圖中html的font-size大小如下:

deviceWidth = 320,font-size = 320 / 6.4 = 50px
deviceWidth = 375,font-size = 375 / 6.4 = 58.59375px
deviceWidth = 414,font-size = 414 / 6.4 = 64.6875px
deviceWidth = 500,font-size = 500 / 6.4 = 78.125px

事實上網易就是這麽幹的,你看它的代碼就知道,body元素的寬是:

技術分享圖片

根據這個可以肯定它的設計稿豎著時的橫向分辨率為640。然後你再看看網易在分辨率為320*680,375*680,414*680,500*680時,html的font-size是不是與上面計算的一致:

技術分享圖片320*680

技術分享圖片375*680

技術分享圖片414*680

技術分享圖片500*680

這個deviceWidth通過document.documentElement.clientWidth就能取到了,所以當頁面的dom ready後,做的第一件事情就是:

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

這個6.4怎麽來的,當然是根據設計稿的橫向分辨率/100得來的。下面總結下網易的這種做法:

  • (1)先拿設計稿豎著的橫向分辨率除以100得到body元素的寬度:
    如果設計稿基於iphone6,橫向分辨率為750,body的width為750 / 100 = 7.5rem
    如果設計稿基於iphone4/5,橫向分辨率為640,body的width為640 / 100 = 6.4rem
  • (2)布局時,設計圖標註的尺寸除以100得到css中的尺寸,比如下圖:
  • 技術分享圖片
  • 播放器高度為210px,寫樣式的時候css應該這麽寫:height: 2.1rem。之所以取一個100作為參照,就是為了這裏計算rem的方便!
  • (3)在dom ready以後,通過以下代碼設置html的font-size:
    document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + ‘px‘;
  • 6.4只是舉個例子,如果是750的設計稿,應該除以7.5。
  • (4)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}
    }
    技術分享圖片 技術分享圖片

最後還有2個情況要說明:

第一,如果采用網易這種做法,視口要如下設置:

<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訪問,看到的就是電腦版的頁面。如果你也想這麽幹,只要把總結中第三步的代碼稍微改一下就行了:

//code from http://caibaojian.com/mobile-responsive-example.html
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + ‘px‘;

3. 淘寶的做法

看看淘寶在不同分辨率下,呈現的效果:

技術分享圖片技術分享圖片技術分享圖片

淘寶的效果跟網易的效果其實是類似的,隨著分辨率的變化,頁面元素的尺寸和間距都相應變化,這是因為淘寶的尺寸也是使用了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的方法如下:

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

淘寶布局的第二個要點,就是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

之前沒有找到這相關的資料,實在不好意思:(

4. 比較網易與淘寶的做法

共同點:

  • 都能適配所有的手機設備,對於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;
}
技術分享圖片 技術分享圖片

5. 如何與設計協作

前端與設計師的協作應該是比較簡單的,最重要的是要規範設計提供給你的產物,通常對於前端來說,我們需要設計師提供標註尺寸後的設計稿以及各種元素的切圖文件,有了這些就可以開始布局了。考慮到Retina顯示屏以及這麽多移動設備分辨率卻不一樣的問題,那麽設計師應該提供多套設計稿嗎?從網易和淘寶的做法來看,應該是不用了,我們可以按照設計稿,先做出一套布局,按照以上方法做適配,由於是等比適配,所以各個設備的視覺效果差異應該會很小,當然也排除不了一些需要媒介查詢特殊處理的情況,這肯定避免不了的。下面這張圖是淘寶設計師分享的他們的工作流程:

技術分享圖片

解釋一下就是:

第一步,視覺設計階段,設計師按寬度750px(iphone 6)做設計稿,除圖片外所有設計元素用矢量路徑來做。設計定稿後在750px的設計稿上做標註,輸出標註圖。同時等比放大1.5倍生成寬度1125px的設計稿,在1125px的稿子裏切圖。

第二步,輸出兩個交付物給開發工程師:一個是程序用到的@3x切圖資源,另一個是寬度750px的設計標註圖。

第三步,開發工程師拿到750px標註圖和@3x切圖資源,完成iPhone 6(375pt)的界面開發。此階段不能用固定寬度的方式開發界面,得用自動布局(auto layout),方便後續適配到其它尺寸。

第四步,適配調試階段,基於iPhone 6的界面效果,分別向上向下調試iPhone 6 plus(414pt)和iPhone 5S及以下(320pt)的界面效果。由此完成大中小三屏適配。

註意第三步,就要使用我們以上介紹的網易跟淘寶的適配方法了。假如公司設計稿不是基於750的怎麽辦,其實很簡單,按上圖做一些相應替換即可,但是流程和方法還是一樣的。解釋一下為什麽要在@3x的圖裏切,這是因為現在市面上也有不少像魅藍note這種超高清屏幕,devicePixelRatio已經達到3了,這個切圖保證在所有設備都清晰顯示。

以上是博主學習移動開發參考的一遍文章,博主分割線以下的總結也是基於以上這篇文章:

原文出處:原文飛機票

——————————————————————————————————我是華麗的分割線———————————————————————————————————

網易rem方案:

前提:

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

優勢:

  不用管DPR,只需知設計稿寬度

已知:

  假設現有iPhone6設計稿,寬750px,其中一元素寬150px;

根據DPR值,iPhone6的DPR值為2,我們可得其中該元素的顯示尺寸:

真實顯示CSS值:

技術分享圖片

現在我們用網易方案來解決這個問題:

  首先我們取1rem = 100px為參考值(這個值可以隨便取,為何取這個值容後解答)

  可知body的寬度:

技術分享圖片

  又因為body的寬度為7.5rem,由“網易公式”可得:

  Html的font-size為:

技術分享圖片

  Dw為deviceWidth,即設備寬度,這是整個方案裏唯一動態改變的值

  現我們已知設計稿為iPhone6,又知iPhone6的設備寬為375px,

  這時候我們再回頭看:

  html當前設備的font-size:

技術分享圖片

  且:

技術分享圖片

  可知,無形中這步已幫我們作了DPR換算;750px的設計稿,顯示在375px的屏幕要怎樣轉換。

  前面我們取了1rem = 100px,可得該元素寬:150px = 1.5rem,

  又知rem為其他元素相對根元素(html)的大小

  所以可得當前元素寬度的真實css顯示值為:1.5rem*50px = 75px;(這裏的75px就跟我們前面理想得到的75px不謀而合了)。

  這邊我們把這個運算再拆解來看:

技術分享圖片

  現再回頭看:就可以知道為什麽當時要取100px為參考值,取這個值的意義就是為了方便運算。

總結:

  我們只需以iPhone6的設計稿(當前主導的機型),750px寬完成一套頁面,當去到其他設備時,因為我們用的都是rem值,只需要通過JS動態獲得當前的dw,再通過動態獲取的dw改變html的font-size值,頁面的其他元素也會因為html的改變而進行等比例縮放。

步驟:

  1.根據設計稿尺寸完成頁面;

  2.設置meta,控制視口寬度,讓頁面以1:1比例渲染頁面

  3.動態設置html的font-size;

  4.把各元素的px值除以100轉換為rem(字體除外)

網易方案關鍵代碼:

設置視口: 

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

動態設置html的font-size:

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

——————————————————————————————————我是華麗的分割線———————————————————————————————————

淘寶rem方案:

(1)根據設計稿尺寸完成頁面切圖。

(2)通過JS獲得當前設備的DPR值,然後動態設置meta的scale值。scale值為縮放值,控制頁面的渲染比例。

  假設當前設計稿寬為750px的Ipone6設計稿,我們也按照這個尺寸實現了頁面。如果當前打開頁面的設備為Iphone6(以下簡稱IP6),IP6的設備寬度為375px,讓375px的視口寬度也實現750px的頁面肯定是裝不下的(顯示不完全,有滾動條)。

  所以我們需要動態設置meta的scale值,通過scale值改變當前的視口寬度。雖然當前的設備寬度仍然為375px,但是我們通過DPR值控制了當前的視口寬度為:

技術分享圖片

  這就相當於我們把750px的頁面放到了750px的設備(通過改變scale值模擬出來的視口)中打開,然後透過375px的設備(當前打開頁面的設備)去觀看(註意:這裏是觀看,不是渲染。) 頁面。

(3)動態設置html的font-size:

    “淘寶公式”:

             技術分享圖片

    假設當前打開的設備為IP6:

            技術分享圖片

    假設當前打開的設備為IP5:

            技術分享圖片

(4)把各元素的設計稿尺寸從px轉換為rem:

            技術分享圖片

    假設當前以IP6為設計稿實現的頁面,其中一元素的寬度為150px,

    根據以上分析可得,當前:

              技術分享圖片

    把150px轉為rem得:

                技術分享圖片

    再假設當前打開頁面的設備為IP5,可得:

                技術分享圖片

    那麽150px的元素在當前頁面顯示的真實尺寸應該為:

                技術分享圖片

    又得:

                技術分享圖片

    通過比例可知當前頁面在不同設備之間實現了等比例縮放,就算再放到其它的手機也一樣會根據動態算出的scale值實現等比例的縮放。

總結:

  我們只需以iPhone6的設計稿(當前主導的機型),750px寬完成一套頁面,通過JS獲取當前設備的DPR值並動態設置meta的scale值。當去到其他設備時,因為我們用的都是rem值,只需要通過JS動態獲得當前的dw,再通過動態獲取的dw改變html的font-size值,頁面的其他元素也會因為html的改變而進行等比例縮放。

淘寶方案關鍵代碼:

動態設置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‘);

以上實則只是在動態設置meta的scale

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

動態設置html的font-size:

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

——————————————————————————————————我是華麗的分割線———————————————————————————————————

對比網易與淘寶的解決方案:

共同點:

     1.都是先根據設計稿,按設計稿原始尺寸完成整套頁面,然後采用rem轉換實現一稿解決所有適應。

    2.都需要動態設置html的font-size屬性,但公式不同。

    3.布局時各元素的尺寸值都是根據設計稿標註的尺寸計算出來,由於html的font-size是動態調整的,所以能夠在不同的設備等比變化。

    4.容器元素的font-size都不用rem,需要額外做font-size的媒體查詢。

不同點:

    1.網易通過設置meta,控制視口寬度為設備寬度,讓頁面以1:1比例渲染;

     淘寶通過動態設置meta的scale,把視口寬度控制為設備的真實設計稿寬度。

    2.運算公式不同:

            html的font-size運算:

                    網易:技術分享圖片

                    淘寶:技術分享圖片

              rem的轉換:

                  網易:把各元素按設計稿的px值除去100轉換為rem;

                  淘寶:各元素rem=設計稿對應px值/html的font-size;

     3.解決思路不同:

            網易:把750px的頁面等比例轉換,壓縮在375px的設備顯示;

            淘寶:把750px的頁面放到虛擬的750px視口渲染打開,再透過375px的設備查看頁面。

備註:本案例分析統一以Iphone6為設計原稿。

  以上就是博主對於移動開發rem使用的一些個人淺見啦,希望能對大家有所幫助吧,說得不好的地方也勞煩各位大神不吝賜教o(╯□╰)o。

如果你不知道什麽是rem:請點擊飛機票;

如果你對於移動web完全沒概念: 請點擊飛機票1 請點擊飛機票2

從網易與淘寶的font-size思考前端設計稿與工作流