移動端Web頁面適配方案

macmakeup699 7年前發布 | 16K 次閱讀 CSS 移動開發

移動端Web頁面,即常說的H5頁面、手機頁面、webview頁面等。

手機設備屏幕尺寸不一,這里總結的是針對移動端設備的頁面,設計與前端實現怎樣做能更好地適配不同屏幕寬度的移動設備。

適配的效果

引用一文章的描述:

在不同尺寸的手機設備上,頁面“相對性的達到合理的展示(自適應)”或者“保持統一效果的等比縮放(看起來差不多)”。

概念理解

viewport視口

viewport是嚴格的等于瀏覽器的窗口。

獲取viewport的尺寸:document. documentElement. clientWidth/Height。

不縮放的視口設置:

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

物理像素(physical pixel)

物理像素又被稱為設備像素,他是顯示設備中一個最微小的物理部件。每個像素可以根據操作系統設置自己的顏色和亮度。所謂的一倍屏、二倍屏(Retina)、三倍屏,指的是設備以多少物理像素來顯示一個CSS像素,也就是說,多倍屏以更多更精細的物理像素點來顯示一個CSS像素點,在普通屏幕下1個CSS像素對應1個物理像素,而在Retina屏幕下,1個CSS像素對應的卻是4個物理像素。

CSS像素

CSS像素是一個抽像的單位,主要使用在瀏覽器上,用來精確度量Web頁面上的內容。一般情況之下,CSS像素稱為與設備無關的像素(device-independent pixel),簡稱DIPs。

設備像素比dpr(device pixel ratio)

設備像素比簡稱為dpr,其定義了物理像素和設備獨立像素的對應關系。它的值可以按下面的公式計算得到:

設備像素比 = 物理像素 / 設備獨立像素

也就是說,二倍屏的dpr是2, 三倍屏是3。

在JavaScript中,可以通過window.devicePixelRatio獲取到當前設備的dpr。而在CSS中,可以通過-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio進行媒體查詢,對不同dpr的設備,做一些樣式適配(這里只針對webkit內核的瀏覽器和webview)。

viewport的scale和dpr是倒數

屏幕密度PPI(pixel per inch)

屏幕密度是指一個設備表面上存在的像素數量,它通常以每英寸有多少像素來計算(PPI)。

設備獨立像素dip或dp

dip或dp,(device independent pixels,設備獨立像素)與屏幕密度有關。dip可以用來輔助區分視網膜設備還是非視網膜設備。

rem(CSS單位)

font size of the root element.

相對于根元素<html>的font-size計算,因此可以通過設置根元素的font-size使得以rem為單位的元素在不同終端上以相對一致的視覺效果呈現。

設 備 設備寬度/pt 根元素font-size/px 寬度/rem
iPhone5 320 16 20
iPhone6 375 18.75 20
i6 Plus 414   20
  360   20

根元素fontSize計算公式:Width/fontSize = baseWidth/baseFontSize

其中,baseWidth, baseFontSize是選為基準的設備寬度及其根元素大小。

缺點:

  • 某些Android設備會丟掉 rem 小數部分。

flex布局

flex布局示意圖

vm/vh(view-width, view-height)

視區寬度/高度為100vw/100vh

視區指瀏覽器內部的可視區域大小:window.innerWidth/Height

upsampling/downsampling

DownSampling: 大圖放入比圖片尺寸小的容器中時,出現像素分割成就近色

不同scale顯示同一圖片基本無問題;

同一sacle,不同倍數圖,存在色差(Downsampling)

實現方案

設計與前端協作方案:

前端實現方案:淘寶手淘:

  • 動態改寫<meta name="viewport">標簽

  • 給<html>元素添加data-dpr屬性,并且動態改寫data-dpr的值

  • 給<html>元素添加font-size屬性,并且動態改寫font-size的值

[淘寶手淘團隊h5頁面終端適配開源庫:lib-flexible]()

各種元素(文本、圖片)處理方案參考:

方案說明:

通過一段JS代碼根據設備的屏幕寬度、dpr設置根元素的data-dpr和font-size, 這段JS代碼要在所有資源加載之前執行,建議做內聯處理。

動態設置data-dpr和meta:viewport

// 對iOS設備進行dpr的判斷,對于Android系列,始終認為其dpr為1。
if (!dpr && !scale) {
    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;
}
// 動態改寫meta:viewport標簽
var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

px轉rem的計算

// 為了方便單位轉換,寫一個px轉換rem的函數
// 淘寶手淘的方案里,i6(375pt)屏幕寬度為10rem,即font-size=75px, scale=0.5 因設計圖為二倍圖,$base-font-size=75px
@function px2em($px, $base-font-size: 16px) {
    @if (unitless($px)) {
        @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
        @return px2em($px + 0px); // That may fail.
    } @else if (unit($px) == em) {
        @return $px;
    }
    @return ($px / $base-font-size) * 1em;
}
// 使用sass的混合宏
@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
    //Conver the baseline into rems
    $baseline-rem: $baseline-px / 1rem * 1;
    //Print the first line in pixel values
    @if $support-for-ie {
        #{$property}: $px-values;
    }
    //if there is only one (numeric) value, return the property/value line for it.
    @if type-of($px-values) == "number"{
        #{$property}: $px-values / $baseline-rem;
    }
    @else {
        //Create an empty list that we can dump values into
        $rem-values:();
        @each $value in $px-values{
            // If the value is zero or not a number, return it
            @if $value == 0 or type-of($value) != "number"{
                $rem-values: append($rem-values, $value / $baseline-rem);
            }
        }
        // Return the property and its list of converted values
        #{$property}: $rem-values;
    }
}

正文文字

  1. 在所有設備大小一樣,

  2. 在更大的設備可以顯示更多文字

  3. 不希望出現13px,15px這樣的尺寸,而是14px, 16px

.a{
  font-size:12px;
}
[data-dpr="2"] .a{
  font-size: 24px;
}
[data-dpr="3"] .a{
  font-size: 36px;
}

為什么要設置viewport和dpr?

適配高密度屏幕手機的px單位,使得不同設備下的px顯示一樣的長度。

CSS像素和縮放、dpr都有關系:在普通手機上,.a字體設置為12px;

在dpr是2的手機上,[data-dpr="2"].a字體為24px,又因為頁面縮放50%,字體為還是12px。

// 不適合用rem適配的字體大小
@mixin font-dpr($font-size){
    font-size: $font-size;

    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }

    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

// 使用:
@include font-dpr(16px);

其他設置根元素fontSize的代碼片段

// JS設置viewport和rem, 整個片段也是以i6(750=375*2)為基準,屏幕寬度分為16rem
var fixScreen = function() {
    var metaEl = doc.querySelector('meta[name="viewport"]'),
        metaCtt = metaEl ? metaEl.content : '',
        matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/),
        matchWidth = metaCtt.match(/width=([^,\s]+)/);

    if ( !metaEl ) { // REM
        var docEl = doc.documentElement,
            maxwidth = docEl.dataset.mw || 750, // 每 dpr 最大頁面寬度
            dpr = isIos ? Math.min(win.devicePixelRatio, 3) : 1,
            scale = 1 / dpr,
            tid;

        docEl.removeAttribute('data-mw');
        docEl.dataset.dpr = dpr;
        metaEl = doc.createElement('meta');
        metaEl.name = 'viewport';
        metaEl.content = 'initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale;
        docEl.firstElementChild.appendChild(metaEl);

        var refreshRem = function() {
            var width = docEl.getBoundingClientRect().width;
            if (width / dpr > maxwidth) {
                width = maxwidth * dpr;
            }
            var rem = width / 16;
            docEl.style.fontSize = rem + 'px';
        };

        //...

        refreshRem();
    }
}

小結

  • 對于多倍屏,通過rem為單位,viewport: scale=1/dpr來達到適合的顯示;

  • 使用iPhone6(375pt, 750px)二倍設計圖:750px為基準;

  • 切圖使用三倍精度圖,以適應三倍屏

  • css單位綜合使用:適配元素rem比例顯示,正文字體宜用px+dpr縮放

  • 配合scss函數,簡化px2rem轉換,且易于維護(若需修改$base-font-size, 無需手動重新計算所有rem單位)

 

來自:https://segmentfault.com/a/1190000008767416

 

 本文由用戶 macmakeup699 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!