首頁 >web前端 >js教程 >行動端頁面開發適配 rem佈局原理

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

高洛峰
高洛峰原創
2016-11-21 17:41:311509瀏覽

行動版頁面開發適配rem佈局原理

什麼是適配,為什麼要適配

我們拿到的設計圖一般是以640,750,1080解析度為基準設計的,而現在的手機終端各式各樣,分辨率不同,邏輯像素不同,視口不同,所以為了讓我們的頁面在每個設備上都可以良好的展示,那麼就需要為這些設備做統一的處理,這個過程就稱為移動端適配。

需要知道的一些概念:

物理像素(physical pixel)

一個物理像素是顯示器(手機螢幕)上最小的物理顯示單元,可以理解為我們平時說的分辨率。

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

設備獨立像素(也叫密度無關像素),可以認為是電腦座標系統中得一個點,這個點代表一個可以由程式使用的虛擬像素(比如: css像素),然後由相關係統轉換為物理像素,在這裡可以理解為我們說的視覺視口的大小;

所以說,物理像素和設備獨立像素之間存在著一定的對應關係,這就是接下來要說的設備像素比。

設備像素比(device pixel ratio)

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

設備像素比也是設備生產的時候設定好的,在javascript中,可以通window.devicePixelRatio取得到目前設備的dpr。

視窗(viewport)

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

行動瀏覽器中視窗分為幾種情況:

中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),當元素的寬度就可以設定為width:6.4rem(640/100),當元素的寬度可以設定為width:6.4rem(640/100),當元素的寬度可以設定為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 設定字體大小,字體大小不可以使用字體大小太大。

以640的設計稿為例最終的設定html font-size程式碼如下,版面時拿設計稿標註的尺寸除以100,就是rem的值,相當簡單啊

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

這裡if(deviceWidth > 640) deviceWidth = 640; 是因為當deviceWidth大於640時物理解析度已經大於1280(取決於dpr),應該去訪問pc的網站;

淘宝的做法:

原理

1) 通过dpr设置缩放比,实现布局视口大小,

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

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-flexible

具体逻辑 :

1)判断head中是否设置了viewport,如果有设置,按照已有viewport 设置缩放比;

if (metaEl) {
        console.warn(&#39;将根据已有的meta标签来设置缩放比例&#39;);
        var match = metaEl.getAttribute(&#39;content&#39;).match(/initial\-scale=([\d\.]+)/);
        if (match) {
            scale = parseFloat(match[1]);
            dpr = parseInt(1 / scale);
        }
    }

2)如果没有设置meta viewport,判断是否设置dpr,如果有,通过dpr计算缩放scale。

        var content = flexibleEl.getAttribute(&#39;content&#39;);
        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(&#39;meta&#39;);
    metaEl.setAttribute(&#39;name&#39;, &#39;viewport&#39;);
    metaEl.setAttribute(&#39;content&#39;, &#39;initial-scale=&#39; + scale + &#39;, maximum-scale=&#39; + scale + &#39;, minimum-scale=&#39; + scale + &#39;, user-scalable=no&#39;);

    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 + &#39;px&#39;;
    flexible.rem = win.rem = rem;

总结:

使用rem布局,实质都是通过动态改写html的font-size基准值,来实现不同设备下的良好统一适配;

网易与淘宝不同 的地方是 ,网易将布局视口设置成了 视觉视口,淘宝将布局视口设置成了物理像素大小,通过 scale缩放嵌入了 视觉视口中;

容器元素的字体大小都不使用rem,需要额外的media查询;


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn