移動端界面的適配

 摘要:在進行移動端界面的書寫的時候,若是把寬度高度或者字體大小所有寫死的話,那麼在全部手機上看到的大小都同樣,存在的問題就是一樣大小的字體,或者一個盒子模型,css

在大屏幕手機上看起來會有點偏小。好比iphone6PLUS。若是是作成適配的話,就很好的解決了這個問題,大屏幕顯示的內容大一點,小屏幕顯示的小一點。html

因此今天作一個移動端頁面適配的小小總結java

 

適配的要求

 

一、在不一樣分辨率的手機上,頁面看起來是自適應的。總體效果看起來比較和諧。不會說大屏幕上看起來特別小。小屏幕上看起來特別大android

二、主要是關注字體,寬高,間距,圖片大小等。git

三、所提供的設計圖通常是手機分辨率的兩倍,才能方便作適配。github

四、使用rem作單位,而不是傳統的pxweb

 

適配的方法,3個步驟

步驟1緩存

設置viewport,也就是平時寫移動端頁面都要加上的:sass

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

 

步驟二、

首先咱們在咱們的頁面引入下面的flexible.js,

這段適配的js代碼是拿淘寶的來用的。

適配的js代碼的github地址以下:https://github.com/amfe/lib-flexible/blob/master/src/flexible.js

 

步驟三、

頁面上咱們的css代碼能夠這樣寫,好比設計圖給咱們的尺寸是750*1000的。某個容器在設計圖的寬度是150px*225px,那咱們在css裏面

寬度:150px/750px/10=150px/75px=2rem;

高度爲:225px/75px=3rem;

一句話:佈局的時候,各元素的css尺寸=設計稿標註尺寸/設計稿橫向分辨率/10;

div{
    width: 2rem;
    height: 3rem;
}

 

經過上面的3個步驟,咱們就能夠將咱們的移動端頁面作成適配的了。

 

 css換算方法

不過有一點,一直算來算去挺煩的。因此在寫css的時候,最好使用css預處理器,好比sass、less來寫,這樣就方便不少了。

或者在sublimeText3中安裝cssREM插件,正常書寫px單位,而後編輯器自動幫你換算成rem.

cssREM插件的安裝教程:https://github.com/flashlizi/cssrem

 

注意點:

容器的寬度高度咱們用rem爲單位,可是字體大小font-size咱們仍是用px,而不是用rem 

緣由:

  flexible.js的做者winter是這樣解釋的:考慮到字體的點陣信息,通常文字尺寸多會採用 16px 20px 24px等值,若以rem指定文字尺寸,會產生諸如21px,19px這樣的值,會致使字形難看,毛刺,甚至黑塊,故大部分文字應該以px設置。

  通常標題類文字,可能也有要求隨屏幕縮放,且考慮到這類文字通常都比較大,超過30px的話,也能夠用rem設置字體。

那麼字體該如何用呢?下面是我用sass寫的一個例子:

 

複製代碼
//編寫一個宏
@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;
    }
}

//元素中調用
.element {
    @include font-dpr(16px);
}
複製代碼

 

 

 

 

 

下面粘貼一下flexible.js的源碼:加了註釋

flexible.js

複製代碼
;(function(win, lib) {
    var doc = win.document;
    var docEl = doc.documentElement;
    var metaEl = doc.querySelector('meta[name="viewport"]');
    var flexibleEl = doc.querySelector('meta[name="flexible"]');
    var dpr = 0;
    var scale = 0;
    var tid;
    var flexible = lib.flexible || (lib.flexible = {});
    
    if (metaEl) {
        console.warn('將根據已有的meta標籤來設置縮放比例');
        var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
        if (match) {
            scale = parseFloat(match[1]);
            dpr = parseInt(1 / scale);
        }
    } else if (flexibleEl) {
        var content = flexibleEl.getAttribute('content');
        if (content) {
            var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
            var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
            if (initialDpr) {
                dpr = parseFloat(initialDpr[1]);
                scale = parseFloat((1 / dpr).toFixed(2));    
            }
            if (maximumDpr) {
                dpr = parseFloat(maximumDpr[1]);
                scale = parseFloat((1 / dpr).toFixed(2));    
            }
        }
    }

    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;
    }
    //爲html標籤添加data-dpr屬性
    docEl.setAttribute('data-dpr', dpr);
    if (!metaEl) {
        metaEl = doc.createElement('meta');
        metaEl.setAttribute('name', 'viewport');
        // 動態設置meta 
        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 = doc.createElement('div');
            wrap.appendChild(metaEl);
            doc.write(wrap.innerHTML);
        }
    }

    //根據dpr和物理像素設置rem
    function refreshRem(){
        //getBoundingClientRect().width至關於物理像素
        var width = docEl.getBoundingClientRect().width;
        // width / dpr > 540等於獨立像素
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;   // 將屏幕寬度分紅10份, 1份爲1rem.  rem轉化px計算公式=d*(width/10)
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }
    // 監聽窗口變化,從新設置尺寸
    win.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
    }, false);

    // 當從新載入頁面時,判斷是不是緩存,若是是緩存,執行refreshRem()
    win.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 300);
        }
    }, false);

    if (doc.readyState === 'complete') {
        doc.body.style.fontSize = 12 * dpr + 'px';
    } else {
        doc.addEventListener('DOMContentLoaded', function(e) {
            doc.body.style.fontSize = 12 * dpr + 'px';
        }, false);
    }
    

    refreshRem();

    flexible.dpr = win.dpr = dpr;
    flexible.refreshRem = refreshRem;
    flexible.rem2px = function(d) {
        var val = parseFloat(d) * this.rem;
        if (typeof d === 'string' && d.match(/rem$/)) {
            val += 'px';
        }
        return val;
    }
    flexible.px2rem = function(d) {
        var val = parseFloat(d) / this.rem;
        if (typeof d === 'string' && d.match(/px$/)) {
            val += 'rem';
        }
        return val;
    }

})(window, window['lib'] || (window['lib'] = {}));
複製代碼

 

 

 

適配中背景圖片的處理

 

一、如何使用background-size

 

由於是使用了rem來作單位,咱們在寫移動端的背景圖的時候,通常使用background-size來控制大小,那要怎麼來換算呢?

換算單位以下:

background-size=背景圖的大小/該設計圖的寬度*10

打個比方:個人背景圖是16*18,設計圖是按照640的寬度來設計的。那麼個人background-size值爲

background-size: 16/640*10rem 16/640*10rem   也就是 background-size:0.25rem 0.28125rem;

經過這樣控制以後,咱們的背景圖也作到了適配的效果

 

二、雪碧圖的適配!!!!

 

剛開始作適配的時候,有一件事是比較頭疼的,那就是雪碧圖的適配,主要是background-size和background-position的配置比較煩。那麼怎麼進行在使用fexible.js的時候適配雪碧圖呢,方法以下:

 

假如我有下面這張雪碧圖,設計圖給個人是按640的分辨率來作的。

 

這張雪碧圖的大小爲200px*458px

 

 

假設如今咱們要用的那個勳子的背景圖。分爲如下幾步:

一、測量勳字這張背景圖的大小,大小爲:75px*85px

二、測量這個勳字在雪碧圖的位置,也就是設置background-position:.經測量,他在雪碧圖的位置爲 x:-123px,y:-7px

三、對着張雪碧圖進行換算:看下面代碼:

知道了上面的尺寸,咱們就行換算便可,將每一個值除以640再乘以10   爲何這麼算,能夠看看源碼

要使用這樣雪碧圖:

1
2
3
4
5
6
7
8
9
10
<!-- 長寬爲: -->
width:  75/640*10=1.171875rem;
height: 85/640*10=1.328125rem;
 
<!-- background-size爲 -->
<!--  由於整張雪碧圖的寬度爲200px, -->
background-size: 200/640*10rem auto;
 
<!-- background-position爲: -->
background-position: -123/640*10rem -7/640*10rem;

  

  

html:

1
< i  class="item1"></ i >

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.item 1 {
     width 75 / 640 * 10 = 1.171875 rem;
     height 85 / 640 * 10 = 1.328125 rem;
     margin 20px  auto ;
     background url ( '../images/itemBg.png' no-repeat ;
     // 由於整張雪碧圖的寬度爲 200px ,
     background- size 200 / 640 * 10 rem  auto ;
     等於
     background- size 3.125 rem  auto ;
 
     // 該背景圖在雪碧圖的位置
     background-position -123 / 640 * 10 rem  -7 / 640 * 10 rem;
     等於
     background-position -1.921875 rem  -0.109375 rem;
     display block ;
}

 

由於換算比較麻煩,因此建議使用sass或者less來進行計算。具體效果我放在了github上,能夠看看:

 https://github.com/xianyulaodi/flexibleDemo

 

 

 

適配的原理解析

 

 

先來了解一些概念

 

在進行分析以前,首先得知道下面這些關鍵性基本概念(術語)。

 

物理像素(physical pixel)

物理像素又被稱爲設備像素,他是顯示設備中一個最微小的物理部件。一個物理像素是顯示器(手機屏幕)上最小的物理顯示單元,在操做系統的調度下,每個設備像素都有本身的顏色值和亮度值。

其實能夠類比爲分辨率。打個比方,一張圖片有n多個很小很小個格子組成。

 

  盜圖,哈哈

 

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

設備獨立像素(也叫密度無關像素),能夠認爲是計算機座標系統中得一個點,這個點表明一個能夠由程序使用的虛擬像素(好比: css像素),而後由相關係統轉換爲物理像素。

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

能夠理解爲css像素,好比寬度爲20px等等。

 

設備像素比(device pixel ratio ),簡稱dpr

設備像素比(devicePixelRatio簡稱dpr)定義了物理像素和設備獨立像素的對應關係,它的值能夠按以下的公式的獲得:

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

在javascript中,能夠經過window.devicePixelRatio獲取當前設備的dpr

css中的px能夠看作是設備的獨立像素,因此經過devicePixelRatio,咱們能夠知道該設備上一個css像素表明多少個物理像素。

例如,在Retina屏的iphone上,devicePixelRatio的值爲2,也就是說1個css像素至關於2個物理像素。

 

再舉個例子:iphone6中:

  1. 設備寬高爲375×667,能夠理解爲設備獨立像素(或css像素)。
  2. dpr爲2,根據上面的計算公式,其物理像素就應該×2,爲750×1334

 

是否是有點頭暈了,能夠看看這篇文章消化一下:http://div.io/topic/1092

 

理解了上面的概念,就比較好理解它的實現原理了

 

理解它的原理有兩點:

 

一、瞭解利用meta標籤對viewport進行控制

 

    咱們能夠看看咱們一般在head裏面加的meta標籤

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

    該meta標籤的做用是讓當前viewport的寬度等於設備的寬度,同時不容許用戶手動縮放。

content="width=device-width,讓viewport的寬度等於設備的寬度,若是不這樣的設定的話,那就會使用那個比屏幕寬的默認viewport,會出現橫向滾動條。
若是改變initial-scale的值,那麼就可讓頁面達到縮放

meta viewport 有6個屬性,能夠了解一下

width 設置layout viewport  的寬度,爲一個正整數,或字符串"device-width"
initial-scale 設置頁面的初始縮放值,爲一個數字,能夠帶小數
minimum-scale 容許用戶的最小縮放值,爲一個數字,能夠帶小數
maximum-scale 容許用戶的最大縮放值,爲一個數字,能夠帶小數
height 設置layout viewport  的高度,這個屬性對咱們並不重要,不多使用
user-scalable 是否容許用戶進行縮放,值爲"no"或"yes", no 表明不容許,yes表明容許

 

 

 

 

 

 

二、淘寶的移動端頁面和flexible.js源碼解析

 

 第一個要點:

淘寶觸屏版佈局的前提就是viewport的scale根據devicePixelRatio(設備像素比) 動態設置:

設備像素比的簡單介紹:http://www.zhangxinxu.com/wordpress/2012/08/window-devicepixelratio/

 

來看一下flexible.js源碼:

根據不一樣的像素設備比,來對頁面進行不一樣的縮放。頁面縮放的 scale=1/dpr ;

 

來看移動端淘寶接下來的三張圖:https://m.taobao.com/#index

三星galasy S4  

data-dpr=1, 因此 initial-scale=1  (由於源碼上 scale = 1 / dpr;)

 

 

iPhone5:

data-drp=2,因此initial-scale=0.5

 

 

iphone 6 Plus 

 

 

第二個要點:

動態設置html的font-size,html元素的font-size的計算公式,font-size = deviceWidth / 10。咱們也能夠看到上面三張截圖的html裏面的font-size是不一樣的

源碼以下:

複製代碼
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
複製代碼

 

其實flexible的實質就幹了如下幾件事

一、動態改寫meta標籤

二、給元素添加data-dpr屬性,而且動態改寫data-dpr的值。也就是動態改寫dpr

三、給元素添加font-size屬性,而且動態改寫font-size的值

 

 

以上就是移動端適配的小小總結,以前只是直接用,沒有好好的理解它的原理。發覺整理的時候,資料查下來也仍是學到不少概念,學到挺多東西的。

你們能夠看看個人參考連接,挺多幹貨的,哈哈。有誤指出,歡迎指出

 

 

參考:

從淘寶適配佈局談移動端適配:

http://www.w3cfuns.com/notes/23659/5e3cd2904a56f5e6b86c4d49e90e0f34.html  

flexible源碼:

https://github.com/amfe/lib-flexible

webApp變革之路之rem

http://isux.tencent.com/web-app-rem.html

設備像素比devicePixelRatio簡單介紹

http://www.zhangxinxu.com/wordpress/2012/08/window-devicepixelratio/

移動端適配方案(上) 

https://github.com/riskers/blog/issues/17

移動端適配方案(下) 

https://github.com/riskers/blog/issues/18

移動端高清、多屏適配方案

http://div.io/topic/1092

使用Flexible實現手淘H5頁面的終端適配

https://github.com/amfe/article/issues/17

相關文章
相關標籤/搜索