使用rem之前,先得弄清楚rem、em和px之间的关系,特别是每一个单位的使用跟代码块的继承之间的关系:
单位代码地址运行后截图说明pxhttps://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/px.html字体恒定没有变化emhttps://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/em.html字体大小依次在减小remhttps://coding.net/u/Jill/p/dankal-jill/git/blob/master/rem/rem.html单位em字体大小是相对直接或者是最近的父级,但单位rem的大小则是相对于html(根元素)字体大小通过对比会发现:只是单位使用不一样但效果却是截然不同的。rem和em都是相对单位,px则不是
在CSS样式表中,单位em是作为字体高度的单位来使用的,但实际字体大小的高度显示是用户对DPI的定义来决定的。为了改善这种样式规则,单位rem则是直接取决于文档根元素字体默认大小,也可以理解为root em,跟em有所不同的是使用rem单位的字体大小在整个文档中都是恒定不变的
rem 的官方定义:The font size of the root element,即以根节点的字体大小作为基准值进行长度计算。
rem的兼容性: 通过上图可见:
大部分主流浏览器支持,但要注意IE9、IE10iOS:6.1系统以上都支持Android:2.1系统以上都支持先不谈安卓,就以iphone各种手机的尺寸来说,iPhone4,5 宽度320px,iPhone6 375px,iPhone6 plus 414px. iPad 768px。如果一个按钮,固定一个75x25的尺寸,那么就必然会导致在不同尺寸下的相对大小不一样。这带来的问题就在于会直接影响到设计的美观,可能在iPhone6下,一个完美的设计图,到了iPhone5,就变得low很多。为了让页面元素的尺寸能够在设备宽度变化的时候也跟着变化,rem就出现了。
使用rem适配的原理就是我们只需要在设备宽度大小变化的时候,调整html的字体大小,那么页面上所有使用rem单位的元素都会相应的变化。 这也是rem与px最大的区别。
在讲述rem布局之前得先搞明白的就是移动设备上的viewport,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta标签的使用,才能更好地让我们的网页适配或响应各种不同分辨率的移动设备。
通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域,即浏览器上(也可能是一个app中的webview)用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,也可能比浏览器的可视区域要小。 下图列出了一些设备上浏览器默认的viewport宽度。
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浏览器默认的viewportlayout viewport 的宽度是大于浏览器可视区域的宽度的visual viewport浏览器可视区域的大小在Android 2, Oprea mini 和 UC 8中无法正确获取ideal viewport移动设备的理想viewport理想适配指的是:1、不需要用户缩放和横向滚动条就能正常的查看网站的所有内容;2、显示的文字的大小是合适,无论是在何种密度屏幕,何种分辨率下,显示出来的大小都是差不多的。当然,不只是文字,其他元素如图片等也如此
文章链接 A tale of two viewports — part one A tale of two viewports — part two 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的毛病:
<meta name="viewport" content="width=device-width, initial-scale=1"> //注意:缩放是相对于ideal viewport来缩放的,缩放值越大,当前viewport的宽度就会越小,反之亦然rem布局就是指为文档的根节点元素设置一个基准字体大小,然后所有的元素尺寸都以rem为单位来写,为了能够在不同尺寸的手机屏幕上自适应,需要用js来判断手机宽度,并动态设置<html>的字体大小,这样基准字体变了,元素的尺寸自然相应变化,达到了自适应的效果。
废话说了辣么多,这里给大家介绍一个移动端布局开发解决方案
使用动态的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/阳阳hotcss提供的将px转为rem的方法,可根据您的需要选择使用。
//px2rem.scss @function px2rem( $px ){ @return $px*320/$designWidth/20 + rem; }推荐使用scss来编写css,在scss文件的头部使用import将px2rem导入,
@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编译工具无法正常编译。
直接写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 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>这是一个最最普通的演示</title> <!-- 根据页面渲染机制,`hotcss.js`必须在其他JS加载前加载,万不可异步加载。 如果可以,你应将`hotcss.js`的内容以内嵌的方式写到`<head>`标签里面进行加载,并且保证在其他js文件之前。 为了避免不必要的bug,请将CSS放到该JS之前加载。 --> <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; } }可以通过强制设置dpr。来关闭响应的viewport scale。使得viewport scale始终为固定值。
<meta name="hotcss" content="initial-dpr=1"> <script src="/path/to/hotcss.js"></script> <!-- 如iphone微信强设dpr=1,则可以长按识别二维码。 注意,强制设置dpr=1后,css中的1px在2x,3x屏上则不再是真实的1px。 -->通过设置该值来优化平板/PC访问体验,注意该值默认值为540。设置为0则该功能关闭。 为了配合使用该设置,请给body增加样式width:16rem;margin:0 auto;。
<meta name="hotcss" content="max-width=640"> <script src="/path/to/hotcss.js"></script> <!-- 默认为540,可根据具体需求自己定义 --> <style> body{ width: 16rem; margin: 0 auto; } </style>通过对design-width的设置可以在本页运行的JS中直接使用hotcss.px2rem/hotcss.rem2px方法,无需再传递第二个值。
<meta name="hotcss" content="design-width=750"> <script src="/path/to/hotcss.js"></script>用于重新计算布局,一般不需要你手动调用。
hotcss.mresize();触发mresize的时候会执行该方法。
hotcss.callback = function(){ //your code here }hotcss.px2rem 和 hotcss.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);https://github.com/imochen/hotcss http://www.cnblogs.com/2050/p/3877280.html
