移動端web app自適應佈局探索與總結

一、困擾多時的問題

在這以前作web app開發的的時候,在自適應方面通常都是寬度經過百分比,高度以iPhone6跟iPhone5之間的一個平衡值寫死,咱們的設計稿都是iPhone5的640 * 1136標準,因此高度通常取個大概值,各類圖標的寬高也是取平衡值寫死,而後部分樣式經過媒體查詢來設置,例如背景圖的多倍圖、基礎字體大小、圖標寬高。css

這樣作的弊端很明顯:html

  1. 作出來的頁面在各類手機端看起來的物理大小(高度)是同樣的,因此在大屏手機會以爲頁面稍小,小屏手機頁面稍大前端

  2. 若是要使高度能更好的適應各類手機屏幕,須要寫太多的媒體查詢樣式,效率低下git

  3. 全屏背景圖片跟頁面元素須要耦合時,元素位置的肯定尤其困難(可能須要經過百分比去肯定元素的橫向位置,但始終會有偏差)github

  4. ...web

最近在微博上看到流雲諸葛總結的一篇文章《從網易與淘寶的font-size思考前端設計稿與工做流》,其中介紹到的幾種web app適配方案,咱們如今的作法剛好是跟拉勾網相似的簡單方案,固然就會有上面我提到的一些問題,最後通過預研和demo測試,咱們採起了網易跟淘寶的方案,其實這二者的方案是大同小異,都是基於rem的適配方案。瀏覽器

二、解決問題的方案

網易跟淘寶的方案介紹在上面流雲諸葛的文章中已經寫的很清楚了,建議能夠先看看那篇文章再閱讀下面我所說的,可能會更加清晰。app

(1)方案的簡單介紹: 基於rem

前提:頁面元素的佈局尺寸全都以設計稿爲基準等比例設置。iphone

html根節點設置一個基礎font-size值,而後頁面的全部元素佈局均相對於該font-size值採用rem單位設定。那麼基礎的font-size值該如何取呢?佈局

假如經過媒體查詢設置font-size,只能解決一部分的狀況,並且並不能完成適配,由於手機屏幕寬度類型實在太多了,因此font-size的取值要經過js計算,取當前viewport的deviceWidth設計稿的寬比例值,例如:咱們的設計稿尺寸都是640px的,iphone5的deviceWidth320px,那麼計算出來的font-size值就是 320 / 640 = 0.5,由於得出的font-size過小,不方便計算,且有的瀏覽器可能不兼容過小字號,因此將font-size放大100倍,因此最終計算出來的font-size爲 320 / 640 * 100 = 50(px); 固然,這個值是根據設計稿來計算的,因此根據計算規則,下面列出幾種常見設計稿相應的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

可在script標籤加上以下代碼

(function () {
    document.addEventListener('DOMContentLoaded', function () {
        var html = document.documentElement;
        var windowWidth = html.clientWidth;
        html.style.fontSize = windowWidth / 6.4 + 'px';
        // 等價於html.style.fontSize = windowWidth / 640 * 100 + 'px';
    }, false);
})();

// 這個6.4就是根據設計稿的橫向寬度來肯定的,假如你的設計稿是750
// 那麼 html.style.fontSize = windowWidth / 7.5 + 'px';

至此,font-size的基礎值就肯定好了,並且知道該font-size值是手機deviceWidth跟設計稿的比例值 的 100倍(重要)

(2)那麼頁面元素該如何設置寬高、邊距...

例如:一個設計稿寬高爲140px的圖標,左邊距爲50px,那麼它的css應該這樣寫

.icon {
    width: 1.4rem; /* 像素換算rem:140px / 100 = 1.4rem */
    height: 1.4rem;
    margin: 0 0 0 .5rem;
}

由於html的font-size是放大了100倍,因此計算rem時,要用設計稿的實際像素除以100,140px / 100 = 1.4rem; 最後實際的像素大小就會由deviceWidth跟設計稿的橫向寬 的 比例 自動計算出來。

如圖iPhone5下面的效果:
圖片描述

iphone6的效果:
圖片描述

能夠看出來:html的font-size動態根據deviceWidth改變,圖標的寬高、邊距等也根據font-size動態按比例變化,大功告成了?不對,相信機智的你已經看到貌似在iPhone6的下有的圖標背景錯位了。。是的,這暴露出了一個背景使用雪碧圖的一個弊端(因爲font-size小數點太多,計算出實際背景圖大小background-size跟背景圖位置background-position時瀏覽器精度不夠可能就會出現位置的誤差(我猜的),這個後面還會詳細講解決方案)

到這裏,設置寬高、邊距等都OK了,接下來...

(3)其餘元素的字體大小該如何設置?

在流雲諸葛的文章中講到,網易跟淘寶的作法都是使用額外的媒體查詢設置幾種字體大小,例如:

@media screen and (max-width: 320px) {
    body{font-size: 14px;}
}
@media screen and (min-width: 321px) and (max-width: 413px) {
    body{font-size: 16px;}
}
@media screen and (min-width: 414px) and (max-width: 639px) {
    body{font-size: 17px;}
}
@media screen and (min-width: 640px) {
    body{font-size: 18px;}
}

可爲何不用rem呢?後來去查了一番資料,發現有一種叫作點陣字體的存在(什麼是點陣字體),也叫做位圖字體,位圖咱們都知道,跟矢量圖是有區別的,就是放大會模糊,因此點陣字體也是放大會模糊的,若是根據rem設置字體大小,字體會自由縮放,可能就會致使點陣字體模糊,因此須要設定使用幾種固定大小的字體。不過,在正常狀況下,系統自帶的字體都是矢量字體,因此使用rem爲單位是沒有問題的,除非你的網頁須要用到特殊的點陣字體。

總結:若是網頁沒有用到特殊的點陣字體,字體單位使用rem,若是用到了點陣字體,字體須要經過媒體查詢設置幾種固定大小的字體

(4)關於背景圖片的錯位問題

上面已經發現了,經過換算rem設置background-size跟background-position的時候,在一些手機型號下會出現背景圖錯位的狀況,但是若是不用rem設置的話,又不能達到適配的目的。(background-size、background-position的rem換算方法跟前面講的寬高設定同樣,都是設計稿尺寸(這時應該是雪碧圖的原始尺寸)除以100倍)

最後通過嘗試,得出了幾種解決方案:
一、如圖(推薦方案):
背景圖錯位

圖標的樣式

.icon {
    width: 1.4rem;
    height: 1.4rem;
    background-image: url(sprite.png);
    background-repeat: no-repeat;
    background-size: 1.4rem;
}

.icon3 {
    background-position: 0 -2.8rem;
}

解決方法,如圖:
背景圖修正

背景圖修正

代碼以下:

.icon-fix {
    background: none;
    position: relative;
    overflow: hidden;
}

.icon-fix:after {
    content: '';
    display: block;
    width: 10000%;
    height: 10000%;
    position: absolute;
    left: 0;
    top: 0;
    background-image: url(sprite.png);
    background-repeat: no-repeat;
    background-size: 140rem;
    -webkit-transform-origin: 0 0;
    -webkit-transform: scale(.01);
    transform-origin: 0 0;
    transform: scale(.01);
}

.icon3:after {
    background-position: 0 -280rem;
}

全部相關代碼 傳送門

二、不使用雪碧圖,使用單個背景圖,這個時候就不存在background-position的須要,只需設定background-size: contain;便可,這樣作的弊端就在於沒法使用雪碧圖,圖片請求增多,適用於頁面圖標較少的狀況

三、使用嵌套img標籤,經過絕對定位模擬background-position,具體請看 responsive-sprites,這種作法須要更多的標籤,且img圖片只能放圖標尺寸大小同樣的雪碧圖,並且不能經過媒體查詢使用多倍圖

以上3中解決方案第一種最優,固然有些特殊狀況可能須要按需選擇!

最後發現一篇研究rem產生小數點像素的問題的文章,感興趣的可戳 《rem 產生的小數像素問題

三、寫在最後

關於web app的探索之路還很長,以上純粹我的在學習過程的一些探索和研究,確定會有不足和錯漏的地方,只有在不斷的實踐中去修正。若是你們發現其中有錯或很差的地方,歡迎提出共同研究,也歡迎你們有更好的方案能夠跟我分享研究!

感謝你的閱讀!

相關文章
相關標籤/搜索