px、em、rem简介
px像素(Pixel),相对长度单位,相对于显示屏幕分辨率
em,相对长度单位,相对于父元素设置的font-size,页面层级越深,em的换算就越复杂。
rem,相对长度单位,相对于HTML根元素设置的font-size,避免了多级嵌套。是CSS3新增的一个相对单位(root em 根em)。
em和rem若没有设置上级字体尺寸,则相对于浏览器的默认字体尺寸16px(所有未经调整的浏览器默认字体都是16px)。
rem基础应用
在使用rem的页面,会给根元素设置一个样式:
html{
font-size: 62.5%;
}
为什么是62.5%呢?
所有未经调整的浏览器默认字体都是16px,1rem等于HTML根节点(或浏览器默认)的字体大小,因此1rem = 16px。
这样不方便px和rem的单位换算,(若设计稿中25px换算成rem,就需要这样计算 25px * 1rem / 16px = 1.5625rem)
假设 1rem = 10px ,那么 100px = 10rem ,20px = 0.25rem 这样换算就简单很多,于是就有了10 / 16 = 62.5%
font-size: 62.5% 就可以理解为,浏览器默认字体为16px,16px * 62.5% = 10px,1rem等于HTML根节点(或浏览器默认)的字体大小,那么1rem = 10px
若设计稿宽度为720px(以iPhone6尺寸设计的设计稿)(设计师给的设计稿是物理分辨率,会是我们写样式的逻辑分辨率的两倍,如果给的设计稿是640,那么是基于iPhone5,320),需要除以2转化为和iPhone6屏幕等宽的375px,那么设计稿中的px宽度转化为CSS代码中的rem就应该这么计算:设计稿中px / 2 / 10 = css中rem。之后再用媒体查询,设置不同屏幕大小上HTML根节点font-size的百分比(详见下文示例)。
62.5%有什么问题?
问题一:上文说“所有未经调整的浏览器默认字体都是16px”,其实并不准确。rem是CSS3的新属性,部分早前浏览器和国内浏览器的默认字体并不是16px,那么10 / 16 的换算规则就不成立了。
问题二:chrome浏览器强制最小字体为12px,若低于12px按照12px处理,那么上文定义的1rem = 10px 就变成了 1rem = 12px,会出现偏差。
建议:为特殊的浏览器设置特殊的HTML根元素字体大小,不建议在pc端使用rem。对于chrome最小字体的限制,建议将换算比例调整为 1rem = 100px(或其它自定的值,但换算规则1rem不能小于12px)。
直接上示例:(前提条件,设计稿是以iPhone5尺寸设计,设计稿宽度为320px * 2 = 640px,规定1rem = 100px)
html{ font-size: 625% }
即以320px宽度的屏幕为标准, 在320px宽度的屏幕下,根字体设置为 625% (即 1rem = 100px),
那么,应用媒体查询修改不同屏幕大小下根元素字体大小:
@media screen and (min-width:360px) and (max-width:374px) and (orientation:portrait) {
html { font-size: 703%; } /* 625% * 360px / 320px = 703.12% */
}
@media screen and (min-width:375px) and (max-width:383px) and (orientation:portrait) {
html { font-size: 732.4%; } /* 625% * 375px / 320px = 732.42% */
}
rem高级应用
625%的方案存在一定的兼容性问题,无法根据不同的设计稿精确适配。网易和淘宝有其自己的适配方案,适配性也很完美,我们可以借鉴。
网易动态font-size
屏幕宽度/设计稿rem宽度=页面动态font-size值
获取页面动态font-size值,再赋值给html元素设置style:
document.documentElement.style.fontSize = document.documentElement.clientWidth / (设计稿px宽度 / 基准值100 = 设计稿rem宽度) + 'px'
淘宝Flexible
github地址:https://github.com/amfe/lib-flexible
Flexible会根据不同屏幕宽度自动设定根font-size、动态viewport、针对Retina屏做的dpr。
直接引用阿里的CDN文件(或下载到本地引入)
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
假设设计稿为750px,Flexible会把设计稿分为10份(Flexible会把设计稿宽度设为10rem),即1rem = 75px,所以根元素的font-size(基准值)为75px
将css换算成rem时:100px = 100px / 75 = 1.33rem
换算工具
不管何种换算方案,px和rem的换算会因为基准值的不同而有些复杂,甚至需要借助计算器的辅助。在这里推荐一个换算神器:cssrem
总结
通用方案
设置根font-size:625%(或其它自定的值,但换算规则1rem不能小于12px);通过媒体查询分别设置每个屏幕的根font-size。
有一定适用性,换算也较为简单。
但,有兼容性的坑,对不同手机适配不是非常精准;需要设置多个媒体查询来适应不同手机,当某款手机尺寸不在设置范围之内,会导致无法适配。
网易方案
拿到设计稿除以100,得到宽度rem值;通过给html的style设置font-size,把得到的宽度rem值代入x ;
document.documentElement.style.fontSize = document.documentElement.clientWidth / x + 'px'
设计稿px/100即可换算为rem。
通过动态根font-size来做适配,基本无兼容性问题,适配较为精准,换算简便。
但,无viewport缩放,且针对iPhone的Retina屏没有做适配,导致对一些手机的适配不是很到位。
淘宝方案
只需要引入Flexible,通过动态根font-size、viewpor、dpr来做适配,无兼容性问题,适配精准。
假设拿到的设计稿是750px,Flexible会把设计稿分为10份,可以理解为页面width=10rem,即1rem=75px,所以根font-size(基准值)=75px。
之后css换算rem公式就是 px / 75 = rem。在没有换算插件的时候计算起来会比较麻烦。
参考资料
教你如何用 lib-flexible 实现移动端H5页面适配
基于淘宝适配方案flexible + 翻屏h5 适配方案adaptive(移动端全屏滑动h5活动解决方案)
与君共勉:再牛逼的梦想,也抵不住傻逼般的坚持!