h5 手机屏幕适配—REM

一、rem、em和px之间的关系

    使用rem之前,先得弄清楚rem、em和px之间的关系,特别是每一个单位的使用跟代码块的继承之间的关系:

单位 代码地址 运行后截图 说明
px https://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/px.html h5 手机屏幕适配—REM_第1张图片 字体恒定没有变化
em https://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/em.html h5 手机屏幕适配—REM_第2张图片 字体大小依次在减小
rem https://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/rem.html h5 手机屏幕适配—REM_第3张图片 单位em字体大小是相对直接或者是最近的父级,但单位rem的大小则是相对于html(根元素)字体大小

    
    通过对比会发现:只是单位使用不一样但效果却是截然不同的。rem和em都是相对单位,px则不是

    在CSS样式表中,单位em是作为字体高度的单位来使用的,但实际字体大小的高度显示是用户对DPI的定义来决定的。为了改善这种样式规则,单位rem则是直接取决于文档根元素字体默认大小,也可以理解为root em,跟em有所不同的是使用rem单位的字体大小在整个文档中都是恒定不变的


二、初识rem

    rem 的官方定义:The font size of the root element,即以根节点的字体大小作为基准值进行长度计算。

    rem的兼容性:
    

    
通过上图可见:

  • 大部分主流浏览器支持,但要注意IE9、IE10
  • iOS:6.1系统以上都支持
  • Android:2.1系统以上都支持

三、rem 为解决什么问题而存在

    先不谈安卓,就以iphone各种手机的尺寸来说,iPhone4,5 宽度320px,iPhone6 375px,iPhone6 plus 414px. iPad 768px。如果一个按钮,固定一个75x25的尺寸,那么就必然会导致在不同尺寸下的相对大小不一样。这带来的问题就在于会直接影响到设计的美观,可能在iPhone6下,一个完美的设计图,到了iPhone5,就变得low很多。为了让页面元素的尺寸能够在设备宽度变化的时候也跟着变化,rem就出现了

    使用rem适配的原理就是我们只需要在设备宽度大小变化的时候,调整html的字体大小,那么页面上所有使用rem单位的元素都会相应的变化。 这也是rem与px最大的区别。


四、利用meta标签对viewport进行控制

    在讲述rem布局之前得先搞明白的就是移动设备上的viewport,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta标签的使用,才能更好地让我们的网页适配或响应各种不同分辨率的移动设备。

1、viewport的概念

    通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域,即浏览器上(也可能是一个app中的webview)用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,也可能比浏览器的可视区域要小。
    下图列出了一些设备上浏览器默认的viewport宽度。
    
浏览器默认的viewport宽度

2、css中的1px并不等于设备的1px

    css中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css中的1px所代表的设备物理像素是不同的。
    在移动端浏览器中以及某些桌面浏览器中,window对象有一个devicePixelRatio属性,它的官方的定义为:

window.devicePixelRatio is the ratio between physical pixels and device-independent pixels (dips) on the device.
window.devicePixelRatio = physical pixels / dips

设备物理像素和设备独立像素的比例,也就是 devicePixelRatio = 物理像素 / 独立像素。css中的px就可以看做是设备的独立像素,所以通过devicePixelRatio,我们可以知道该设备上一个css像素代表多少个物理像素。
    需要注意的是,devicePixelRatio存在兼容性问题,具体可以查看PPK made some research on devicePixelRatio
    
拓展:PPK的关于三个viewport的理论
    ppk把移动设备上的viewport分为layout viewport 、 visual viewport 和 ideal viewport 三类,其中的ideal viewport是最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度,只要在css中把某一元素的宽度设为ideal viewport的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。

类别 简述 说明 图例
layout viewport 浏览器默认的viewport layout viewport 的宽度是大于浏览器可视区域的宽度的 layout viewport
visual viewport 浏览器可视区域的大小 在Android 2, Oprea mini 和 UC 8中无法正确获取 visual viewport
ideal viewport 移动设备的理想viewport 理想适配指的是:1、不需要用户缩放和横向滚动条就能正常的查看网站的所有内容;2、显示的文字的大小是合适,无论是在何种密度屏幕,何种分辨率下,显示出来的大小都是差不多的。当然,不只是文字,其他元素如图片等也如此 ideal viewport1ideal viewport2

    

文章链接
A tale of two viewports — part one
A tale of two viewports — part two
Meta viewport

3、利用meta标签对viewport进行控制

在苹果的规范中,meta viewport 有6个指令,[可以同时使用,也可以单独使用或混合使用,多个指令同时使用时用逗号隔开]如下:

指令 说明
width 设置layout viewport 的宽度,为一个正整数,或字符串”width-device”
initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
height 设置layout viewport 的高度,这个属性对我们并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为”no”或”yes”, no 代表不允许,yes代表允许

    
    要把当前的viewport宽度设为ideal viewport的宽度,既可以设置 width=device-width,也可以设置 initial-scale=1,但这两者各有一个小缺陷,就是iphone、ipad以及IE 会横竖屏不分[下图所示],通通以竖屏的ideal viewport宽度为准。所以,最完美的写法应该是,两者都写上去,这样就initial-scale=1解决了 iphone、ipad的毛病,width=device-width则解决了IE的毛病:

"viewport" content="width=device-width, initial-scale=1">
//注意:缩放是相对于ideal viewport来缩放的,缩放值越大,当前viewport的宽度就会越小,反之亦然

五、rem布局

rem布局基本概念

    rem布局就是指为文档的根节点元素设置一个基准字体大小,然后所有的元素尺寸都以rem为单位来写,为了能够在不同尺寸的手机屏幕上自适应,需要用js来判断手机宽度,并动态设置的字体大小,这样基准字体变了,元素的尺寸自然相应变化,达到了自适应的效果。

    废话说了辣么多,这里给大家介绍一个移动端布局开发解决方案

hotcss

  • 使用动态的HTML根字体大小和动态的viewport scale。

  • 遵循视觉一致性原则。在不同大小的屏幕和不同的设备像素密度下,让你的页面看起来是一样的。

  • 不仅便捷了你的布局,同时它使用起来异常简单。

示例名称 演示地址 贡献者
普通的演示 http://imochen.github.io/hotcss/example/normal/ 墨尘
duang游戏 http://imochen.github.io/hotcss/example/duang/ 阳阳
灰太狼 http://imochen.github.io/hotcss/example/wolf/ 阳阳
优势
  • 保证不同设备下的统一视觉体验。
  • 不需要你再手动设置viewport,根据当前环境计算出最适合的viewport
  • 支持任意尺寸的设计图,不局限于特定尺寸的设计图。
  • 支持单一项目,多种设计图尺寸,专为解决大型,长周期项目。
  • 提供px2rem转换方法,CSS布局,零成本转换,原始值不丢失。
  • 有效解决移动端真实1像素问题。
用法
1、 引入hotcss.js
<script src="/path/to/hotcss.js">script>
2、css要怎么写

hotcss提供的将px转为rem的方法,可根据您的需要选择使用。

//px2rem.scss
@function px2rem( $px ){
     
    @return $px*320/$designWidth/20 + rem;
}

推荐使用scss来编写css,在scss文件的头部使用importpx2rem导入,

@import '/path/to/px2rem.scss';

如果你的项目是单一尺寸设计图,那么你需要去px2rem.scss中定义全局的designWidth

@function px2rem( $px ){
     
    @return $px*320/$designWidth/20 + rem;
}
$designWidth : 750; //如设计图是750

如果你的项目是多尺寸设计图,那么就不能定义全局的designWidth了。需要在你的业务scss中单独定义。如以下是style.scss

@import '/path/to/px2rem.scss';
$designWidth : 750; //如设计图是750

$designWidth必须要在使用px2rem前定义。否则scss编译会出错。

注意:如果使用less,则需要引入less-plugin-functions,普通的less编译工具无法正常编译。

3、想用px怎么办?

直接写px肯定是不能适配的,那hotcss.js会在html上注册data-dpr属性,这个属性用来标识当前环境dpr值。那么要使用px可以这么写。

//scss写法
#container{
    font-size: 12px ;
    [data-dpr="2"] &{
        font-size: 24px;
    }
    [data-dpr="3"] &{
        font-size: 36px;
    }
}

可能你会说 talk is cheap,show me the code,那我现在列下hotcss整个项目的目录结构。

├── example //所有的示例都在这个目录下
│   ├── duang
│   ├── normal
│   └── wolf
│
└── src //主要文件在这里
    ├── hotcss.js
    ├── px2rem.less
    ├── px2rem.scss
    └── px2rem.styl
  • hotcss.js
(function( window , document ){

    'use strict';

    //给hotcss开辟个命名空间,别问我为什么,我要给你准备你会用到的方法,免得用到的时候还要自己写。
    var hotcss = {};

    (function() {
        //根据devicePixelRatio自定计算scale
        //可以有效解决移动端1px这个世纪难题。
        var viewportEl = document.querySelector('meta[name="viewport"]'),
            hotcssEl = document.querySelector('meta[name="hotcss"]'),
            dpr = window.devicePixelRatio || 1,
            maxWidth = 540,
            designWidth = 0;

        dpr = dpr >= 3 ? 3 : ( dpr >=2 ? 2 : 1 );

        //允许通过自定义name为hotcss的meta头,通过initial-dpr来强制定义页面缩放
        if (hotcssEl) { var hotcssCon = hotcssEl.getAttribute('content'); if (hotcssCon) { var initialDprMatch = hotcssCon.match(/initial\-dpr=([\d\.]+)/); if (initialDprMatch) { dpr = parseFloat(initialDprMatch[1]); } var maxWidthMatch = hotcssCon.match(/max\-width=([\d\.]+)/); if (maxWidthMatch) { maxWidth = parseFloat(maxWidthMatch[1]); } var designWidthMatch = hotcssCon.match(/design\-width=([\d\.]+)/); if (designWidthMatch) { designWidth = parseFloat(designWidthMatch[1]); } } }

        document.documentElement.setAttribute('data-dpr', dpr);
        hotcss.dpr = dpr;

        document.documentElement.setAttribute('max-width', maxWidth);
        hotcss.maxWidth = maxWidth;

        if( designWidth ){ document.documentElement.setAttribute('design-width', designWidth); hotcss.designWidth = designWidth; }

        var scale = 1 / dpr,
            content = 'width=device-width, initial-scale=' + scale + ', minimum-scale=' + scale + ', maximum-scale=' + scale + ', user-scalable=no';

        if (viewportEl) { viewportEl.setAttribute('content', content); } else { viewportEl = document.createElement('meta'); viewportEl.setAttribute('name', 'viewport'); viewportEl.setAttribute('content', content); document.head.appendChild(viewportEl); }

    })();

    hotcss.px2rem = function( px , designWidth ){
        //预判你将会在JS中用到尺寸,特提供一个方法助你在JS中将px转为rem。就是这么贴心。
        if( !designWidth ){
            //如果你在JS中大量用到此方法,建议直接定义 hotcss.designWidth 来定义设计图尺寸;
            //否则可以在第二个参数告诉我你的设计图是多大。
            designWidth = parseInt(hotcss.designWidth , 10);
        }

        return parseInt(px,10)*320/designWidth/20;
    }

    hotcss.rem2px = function( rem , designWidth ){
        //新增一个rem2px的方法。用法和px2rem一致。
        if( !designWidth ){
            designWidth = parseInt(hotcss.designWidth , 10);
        }
        //rem可能为小数,这里不再做处理了
        return rem*20*designWidth/320;
    }

    hotcss.mresize = function(){
        //给HTML设置font-size。
        var innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth;

        if( hotcss.maxWidth && (innerWidth/hotcss.dpr > hotcss.maxWidth) ){
            innerWidth = hotcss.maxWidth*hotcss.dpr;
        }

        if( !innerWidth ){ return false;}

        document.documentElement.style.fontSize = ( innerWidth*20/320 ) + 'px';

        hotcss.callback && hotcss.callback();

    };

    hotcss.mresize(); 
    //直接调用一次

    window.addEventListener( 'resize' , function(){ clearTimeout( hotcss.tid ); hotcss.tid = setTimeout( hotcss.mresize , 33 ); } , false ); 
    //绑定resize的时候调用

    window.addEventListener( 'load' , hotcss.mresize , false ); 
    //防止不明原因的bug。load之后再调用一次。


    setTimeout(function(){ hotcss.mresize();  //防止某些机型怪异现象,异步再调用一次 },333)

    window.hotcss = hotcss; 
    //命名空间暴露给你,控制权交给你,想怎么调怎么调。


})( window , document );

栗子:

//.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>这是一个最最普通的演示title>
    
    <link rel="stylesheet" href="./css/style.css">
    <script src="../hotcss.js">script>
head>
<body>
    <div id="header">普通的演示div>
    <div id="container1">
        这是一个普通的演示。在head头加载hotcss.js。
        优雅的使用scss书写css。单位均使用了px2rem处理
    div>
    <div id="container2">
        这个里面的字体没有使用px2rem。具体写法参看css。
        如果你在使用chrome。请打开控制台,尝试模拟不同设备,来查看表现。
    div>
body>
html>
//.scss
@import 'px2rem'; //第一步先把px2rem导入

$designWidth : 640; //写scss之前,必须要先定义designWidth。


body{
    width: 16rem;
    margin: 0 auto;
    padding: 0;
}

#header{
    width: px2rem(640);
    height: px2rem(88);
    line-height: px2rem(88);
    background-color: #33aa33;
    text-align: center;
    font-size: px2rem(48);
    color: rgba(255,255,255,1);
}

#container1{
    margin-top: px2rem(10);
    padding: px2rem(30);
    background-color: #191919;
    color: #f0f0f0;
    line-height: 1.7;
    max-height: 100%;
    font-size: px2rem(32);
}

#container2{
    margin-top: px2rem(10);
    padding: px2rem(30);
    background-color: #191919;
    color: #f0f0f0;
    line-height: 1.7;
    max-height: 100%;
    font-size: 12px ;
    [data-dpr="2"] &{
        font-size: 24px;
    }
    [data-dpr="3"] &{
        font-size: 36px;
    }
}
接口说明

initial-dpr

可以通过强制设置dpr。来关闭响应的viewport scale。使得viewport scale始终为固定值。

<meta name="hotcss" content="initial-dpr=1">
<script src="/path/to/hotcss.js">script>

max-width

通过设置该值来优化平板/PC访问体验,注意该值默认值为540。设置为0则该功能关闭。
为了配合使用该设置,请给body增加样式width:16rem;margin:0 auto;

<meta name="hotcss" content="max-width=640">
<script src="/path/to/hotcss.js">script>

<style>
body{
    width: 16rem;
    margin: 0 auto;
}
style>

design-width

通过对design-width的设置可以在本页运行的JS中直接使用hotcss.px2rem/hotcss.rem2px方法,无需再传递第二个值。

<meta name="hotcss" content="design-width=750">
<script src="/path/to/hotcss.js">script>

hotcss.mresize

用于重新计算布局,一般不需要你手动调用。

hotcss.mresize();

hotcss.callback

触发mresize的时候会执行该方法。

hotcss.callback = function(){
     
  //your code here
}

单位转换hotcss.px2rem/hotcss.rem2px

hotcss.px2remhotcss.rem2px你可以预先设定hotcss.designWidth可以在meta中设置design-width,则之后使用这两个方法不需要再传递第二个参数。

迭代后仍然支持在js中设置hotcss.designWidth,推荐使用meta去设置。

/**
* [px2rem px值转换为rem值]
* @param  {[number]} px          [需要转换的值]
* @param  {[number]} designWidth [设计图的宽度尺寸]
* @return {[number]}             [返回转换后的结果]
*/
hotcss.px2rem( px , designWidth );

/**
* 同上。
* 注意:因为rem可能为小数,转换后的px值有可能不是整数,需要自己手动处理。
*/
hotcss.rem2px( rem , designWidth );


//你可以在meta中定义design-width,此后使用px2rem/rem2px,就不需要传递designWidth值了。同时也支持旧的设置方式,直接在JS中设置hotcss.designWidth
hotcss.px2rem(200);
hotcss.rem2px(350);

六、使用rem的线上站点

使用rem的大站

  • 手机淘宝
  • 网易新闻
  • 聚划算

使用hotcss的站点

  • 熊猫TV
  • 美丽说HIGO
  • 奇虎360
  • 爆米兔
  • 一起作业
  • TalkingData
  • 电兔贷款
  • 新浪show

七、参考链接

https://github.com/imochen/hotcss
http://www.cnblogs.com/2050/p/3877280.html

你可能感兴趣的:(开发者手册,rem,h5手机屏幕适配,hotcss,viewport)