移動端頁面開發適配 rem佈局原理

移動端頁面開發適配 rem佈局原理

什麼是適配,爲何要適配

咱們拿到的設計圖通常是以640,750,1080分辨率爲基準設計的,而如今的手機終端各式各樣,分辨率不一樣,邏輯像素不一樣 ,視口不一樣,因此爲了讓咱們的頁面在每一個設備上均可以良好的展現,那麼就須要爲這些設備作統一的處理,這個過程就稱爲移動端適配。javascript

須要知道的一些概念:

物理像素(physical pixel)css

一個物理像素是顯示器(手機屏幕)上最小的物理顯示單元,能夠理解爲咱們平時說的分辨率。html

設備獨立像素(density-independent pixel)java

設備獨立像素(也叫密度無關像素),能夠認爲是計算機座標系統中得一個點,這個點表明一個能夠由程序使用的虛擬像素(好比: css像素),而後由相關係統轉換爲物理像素,在這裏能夠理解爲咱們說的視覺視口的大小;android

因此說,物理像素和設備獨立像素之間存在着必定的對應關係,這就是接下來要說的設備像素比。css3

設備像素比(device pixel ratio)git

設備像素比(簡稱dpr)定義了物理像素和設備獨立像素的對應關係,它的值能夠按以下的公式的獲得:
設備像素比 = 物理像素 / 設備獨立像素 // 在某一方向上,x方向或者y方向github

設備像素比也是設備生產的時候設置好的,在javascript中,能夠通window.devicePixelRatio獲取到當前設備的dpr。web

視口(viewport)

pc端視口指瀏覽器窗口內的內容區域,不包含工具條,滾動條.瀏覽器


移動瀏覽器中視口分爲幾種狀況:

  • <metaname="viewport"content=「width=device-width,minimum-scale=1.0,maximum-scale=1.0」/>中content所設置的視口,稱爲佈局視口,最大值由瀏覽器廠商規定 ,能夠document.documentElement.clientWidth獲取其寬度.

  • 而咱們看到的瀏覽器的窗口,網頁區域的大小,稱爲視覺視口,用css像素表示(設備邏輯像素)

rem

rem是css3 的一個長度單位 ,相對文檔跟元素 html;好比設置html font-size=100px;那麼1rem=100px;以後的全部元素均可以用這個基準值來設置大小;

經常使用的方案:

  • 固定高度,寬度自適應(百分比,em)

  • 使用 rem佈局

下面總結了網易 淘寶首頁使用rem的方案

網易的作法:

1) 將佈局適口設置爲視覺視口,不進行縮放,即理想視口。

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

2) 以設計稿分辨率爲基準,取100px爲font-size的參照,那麼設計稿的寬若是是640,body元素的寬度就能夠設置爲width:6.4rem(640/100),當咱們將佈局視口設置爲320時,因而html的font-size=deviceWidth / 6.4。


3) 經過document.documentElement.clientWidth獲取deviceWidth;


4) 當頁面的dom ready後設置html font-size,

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

5) 經過mediaQuery 設置字體大小,字體大小不可使用rem,緣由是偏差太大。


以640的設計稿爲例最終的設置html font-size代碼以下,佈局時拿設計稿標註的尺寸除以100,就是rem的值,至關簡單啊

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

這裏if(deviceWidth > 640) deviceWidth = 640; 是由於當deviceWidth大於640時物理分辨率已經大於1280(取決於dpr),應該去訪問pc的網站;

淘寶的作法:

原理

1) 經過dpr設置縮放比,實現佈局視口大小,

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’;

這裏的意思是,clientWidth / 10 獲得是佈局視口下的rem基準值(以iphone6爲例 1rem=75px),那麼設計稿正好也是 750,因此對應的關係 clientWidth / 10==設計稿的尺寸/x, 那麼x=設計稿的尺寸/rem基準值。
若是是iphone6 plus rem基準值等於clientWidth / 10 等於124.2,那麼x=750/124.2。


關於具體的實現 淘寶提供了一個開源的方案lib-flexible:https://github.com/amfe/lib-f...

具體邏輯 :

1)判斷head中是否設置了viewport,若是有設置,按照已有viewport 設置縮放比;

if (metaEl) {
        console.warn('將根據已有的meta標籤來設置縮放比例');
        var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
        if (match) {
            scale = parseFloat(match[1]);
            dpr = parseInt(1 / scale);
        }
    }

2)若是沒有設置meta viewport,判斷是否設置dpr,若是有,經過dpr計算縮放scale。

var content = flexibleEl.getAttribute('content');
        if (content) {
            var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
            var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);//maximum 設置最大值,與initial的值比較,取最小值;
            if (initialDpr) {
                dpr = parseFloat(initialDpr[1]);
                scale = parseFloat((1 / dpr).toFixed(2));    
            }
            if (maximumDpr) {
                dpr = parseFloat(maximumDpr[1]);
                scale = parseFloat((1 / dpr).toFixed(2));    
            }
        }

3)若是 dpr &scale都沒有設置,那麼就經過設備的dpr設置起縮放 scale,

if (!dpr && !scale) {//meta[name="viewport"]&&meta[name="flexible"]都不存在。
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,對於2和3的屏,用2倍的方案,其他的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
            dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
            dpr = 2;
        } else {
            dpr = 1;
        }
    } else {
        // 其餘設備下,仍舊使用1倍的方案
        dpr = 1;
    }
    scale = 1 / dpr;
}

4)獲得scale以後 ,若是meta 的viewport不存在,那麼就建立一meta[name=「viewport」],將scale配置進去。

metaEl = doc.createElement('meta');
    metaEl.setAttribute('name', 'viewport');
    metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

    if (docEl.firstElementChild) {

        docEl.firstElementChild.appendChild(metaEl);
         
    }

5)動態改寫html的font-size

var width = docEl.getBoundingClientRect().width;//獲取html的寬度
    if (width / dpr > 540) {//判斷屏幕邏輯像素大於540時,取540
        width = 540 * dpr;
    }
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;

總結:

  • 使用rem佈局,實質都是經過動態改寫html的font-size基準值,來實現不一樣設備下的良好統一適配;

  • 網易與淘寶不一樣 的地方是 ,網易將佈局視口設置成了 視覺視口,淘寶將佈局視口設置成了物理像素大小,經過 scale縮放嵌入了 視覺視口中;

  • 容器元素的字體大小都不使用rem,須要額外的media查詢;


參考文章連接:
http://www.cnblogs.com/lyzg/p...
http://mobile.51cto.com/web-4...

相關文章
相關標籤/搜索