h5 移動端適配方案思考

基礎概念

CSS像素(CSS pixels)

這個是瀏覽器使用的抽象單位,用來精確度量網頁上的內容。平時常常寫的width:100px;height:100px;都是與設備無關的。css

設備獨立像素(device independent pixels),也能夠稱爲設備無關的邏輯像素

meta裏面設置width=device-width,這個device-width就是設備獨立像素android

在chrome裏 看到的ip6爲375667,ip4爲320480等等都是設備獨立像素,它們在數值上與css數值是相等的web

設備像素(device pixels ),也能夠稱爲物理像素

是顯示屏的最小物理單位,每一像素都包含本身的顏色、亮度。像素是沒有大小的、是一個抽象概念、是一個相對單位。 關於像素有一個常見的錯誤理解:認爲像素是一個寬高相等的小方塊,而且的像素都是「那麼大」,可是不知道這個寬高的具體數字。chrome

分辨率

泛指量測或顯示系統對細節的分辨能力。以ip6手機屏幕爲例,分辨率爲750×1334,這是指屏幕縱向能顯示1920個像素,橫向能顯示1080個像素瀏覽器

設備像素比,也成dpr

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

適配方案1-固定viewport

好處:爲了寬屏顯示更多內容iphone

平常的 h5 項目使用 viewport 的 initail-scale 爲 1,寬度設置配合百分比佈局,1px 問題使用 transform 方案會最方便。因爲每種設備的設備獨立像素不一樣,最終效果也不一樣,最後的視覺效果以下:佈局

問題:若是設計稿中給的是某邊框線是 1px,那麼按照上述規則,就得設置這個邊框爲 0.5px,可是部分機型不會支持小數點的 px 尺寸。字體

爲了獲得極細緻的真實 1px 單位的邊框,衍生出了不少的解決辦法,使用的比較多的有兩種解決方案。其一爲 transform 縮放,其二爲動態 viewport。scala

transfrom 方案,能夠搭配僞元素來使用,若是隻是爲了獲得底邊的話,那麼設置爲高度 1px,而後縮放 y 軸爲 0.5。

.scale {
    position: relative;
}
.scale:after {
    content: "";
    position: absolute;
    bottom: 0px;
    left: 0px;
    right: 0px;
    border-bottom: 1px solid #ddd;
    -webkit-transform: scaleY(.5);
            transform: scaleY(.5);
    -webkit-transform-origin :0 0;
            transform-origin :0 0; 
}

若是須要設置四邊的話,則這麼設置

.scale:after{
    content: "";
    pointer-events: none; /* 防止點擊觸發 */
    box-sizing: border-box;
    position: absolute;
    width: 200%;
    height: 200%;
    left: 0;
    top: 0;
    border-radius: 8px;
    border:1px solid #999;
    -webkit-transform: scale(.5);
            transform: scale(.5);
    -webkit-transform-origin: 0 0;
            transform-origin: 0 0;
}

適配方案2-動態 viewport 和 REM 適配

若是是電商的活動頁這種對視覺效果比較嚴謹的,則使用rem和動態viewport方案,最終的視覺效果以下:

源碼以下面,基礎思想就是設置根節點元素上得font-size,使之爲十六分之一屏幕寬度(相似柵格系統,淘寶爲1/10分屏寬,貝貝1/16屏寬)。在設置viewport爲1/drp的值就能夠了。

;(function(win) {
    var h;
    var dpr = win.navigator.appVersion.match(/iphone/gi)?win.devicePixelRatio:1;
    var scale = 1 / dpr;
    var docEl = document.documentElement;
    var metaEl = document.createElement('meta');
    function setUnitA(){
        win.rem = docEl.getBoundingClientRect().width / 16;
        docEl.style.fontSize = win.rem + 'px';
    }
    win.dpr = dpr;
    win.addEventListener('resize', function() {
        clearTimeout(h);
        h = setTimeout(setUnitA, 300);
    }, false);
    win.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(h);
            h = setTimeout(setUnitA, 300);
        }
    }, false);
    docEl.setAttribute('data-dpr', dpr);
    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);
    } else {
        var wrap = document.createElement('div');
        wrap.appendChild(metaEl);
        document.write(wrap.innerHTML);
    }
    setUnitA();
})(window);

iPhone6計算出的根節點元素的font-size爲__750px/16=46.876px__,那麼跟着設計稿的尺寸,css單位應該這麼寫:css寫的尺寸(單位爲rem) = 設計稿裏的元素尺寸 / 46.875。這種方案,頁面上使用了rem單位的元素在不一樣倍率手機下css尺寸都不一樣,例如在iphone5裏,css尺寸就是__設計稿元素尺寸 / 46.875 * 40

然而事情尚未完,若是設計師但願能讓大屏的狀況顯示更多的字,而非把字給這樣放大了,那麼字體則不能使用rem爲單位。看下面的一段代碼

.px2px(@name, @px){
    @{name}: round(@px / 2) * 1px;
    [data-dpr="2"] & {
        @{name}: @px * 1px;
    }
    // for mx3
    [data-dpr="2.5"] & {
        @{name}: round(@px * 2.5 / 2) * 1px;
    }
    // for 小米note
    [data-dpr="2.75"] & {
        @{name}: round(@px * 2.75 / 2) * 1px;
    }
    [data-dpr="3"] & {
        @{name}: round(@px / 2 * 3) * 1px
    }
    // for 三星note4
    [data-dpr="4"] & {
        @{name}: @px * 2px;
    }
}
.fontSize(@px) {
    .px2px(font-size, @px);
}

用法爲.fontSize(設計稿裏此元素的字體大小) ;,這樣就能獲得不一樣倍率下正確的字體大小,不過此法仍然有一個問題,須要窮舉出全部的dpr狀況,android機子碎片化很是嚴重,因此總會有一些奇奇怪怪的機型效果不如意。

相關文章
相關標籤/搜索