移动端界面的适配

 摘要:在进行移动端界面的书写的时候,若是把宽度高度或者字体大小所有写死的话,那么在全部手机上看到的大小都同样,存在的问题就是一样大小的字体,或者一个盒子模型,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

相关文章
相关标签/搜索