背景
虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。
本文中不涉及一些viewport、dpr等的概念介绍,详细了解可以再查看本博客中另一篇文章有具体讲解这些概念。
EM和REM
使用REM+媒体查询方式进行编写自适应方案时,先来了解下EM和REM是什么?
EM
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
EM的特点
- em的值并不是固定的
- em会继承父级元素的字体大小
注意:任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。为了简化font-size的换算,需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。
所以我们在写CSS的时候,需要注意两点:
- body选择器中声明Font-size=62.5%;
- 将你的原来的px数值除以10,然后换上em作为单位;
- 重新计算那些被放大的字体的em数值。避免字体大小的重复声明。
也就是避免1.2 * 1.2= 1.44的现象。比如说你在#content中声明了字体大小为1.2em,那么在声明p的字体大小时就只能是1em,而不是1.2em, 因为此em非彼em,它因继承#content的字体高而变为了1em=12px。
REM
rem
是CSS3
新增的一个相对单位(root em,根em),这个单位引起了广泛关注。这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。目前,除了IE8及更早版本外,所有浏览器均已支持rem。
简单的理解,rem就是相对于根元素<html>
的font-size
来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>
的font-size
计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。
媒体查询 + Rem实现自适应
放上代码中所使用的设计稿和图片,自行右键保存。图片来源手淘H5适配方案
该设计图是按照iPhone6作为基准设计尺寸,iPhone6的分辨率为750px * 1334px
,iPhone6的DPR为2,则CSS像素则缩小为设计稿尺寸的1/2
。既设计稿量出某宽为20px,则css像素则转为为10px。
理想适口的缩放比为1的情况下
首先按照设计稿尺寸还原页面,为了方便理解,首先使用px还原页面,在iPhone6下显示设计。
1 |
|
编写后页面显示,当然这里是举例,有些像素为了方便计算,只是大概的测量了一下,这里使用的测量工具为Mark Man
。
然后看看其他设备显示的效果,因为这里使用的是流式布局
,即百分比布局,页面还没有说变形很严重,但是在iPhone5设备上或者更小的设备上显示就会显得页面元素偏大,而在一些ipad就显得更为难受了。(换成其他DPR下情况也是相同)。
这里不讲解媒体查询是什么和具体语法,详细了解可以查看MDN
而该方案就是基于rem的原理,针对不同屏幕尺寸的改变来改变根节点html的font-size
的大小。
这里总结出了一个公式:
1 | font-size(rem) = 预设font-size(rem)基准值 / (设计稿宽度 / DPR) * 设备宽度 |
该公式的原理就是先根据设计稿的尺寸和DPR求出设备的宽度,根据该设备的宽度下预设一个font-size
的基准值,再求出该设备下的宽度与预设基准值的比值,然后其他设备下的设备宽度除以该基准值就可以求出其他设备下的html的font-size
的值。所以上述公式是由下条公式变化得来的。
1 | font-size(rem) = 设备宽度 / ((设计稿宽度 / DPR) / 预设font-size(rem)基准值) |
按照本文中设计稿为iPhone6的尺寸设计,我们以设计稿下iPhone6为375px
的html的font-size
预设基准值为100px
(方便计算),即1rem = 100px
,则其他设备像素下html的font-size
的值为
- iPhone5的设备像素320px:
100 / (750 / 2) * 320 = 85.333px
- iPhone6的设备像素375px:
100px
- iPhone6Plus的设备像素414px:
100 / (750 / 2) * 414 = 110.4px
只要以设计稿下预设的基准值再根据其他屏幕来换算计算出其他设备下的html的font-size
大小即可。
页面中再根据1rem = 100px
将页面中px单位换算成rem即可。再添加上根据设备宽度的媒体查询设置根节点的font-size
大小。
1 | /* base-rem = 100px */ |
更改后整体页面代码
1 |
|
适配后
图片较大,可自行运行代码在dpr为1、2、3下再更改屏幕尺寸,运行结果良好,可谓够用。
为什么可谓够用,该方案有缺点:通过设备宽度范围区间这样的媒体查询来动态改变rem基准值,其实不够精确,比如:宽度为360px 和 宽度为320px的手机,因为屏宽在同一范围区间内(<375px),所以会被同等对待(rem基准值相同),而事实上他们的屏幕宽度并不相等,它们的布局也应该有所不同。最终,结论就是:这样的做法,没有做到足够的精确,但是够用。
Less优化
如果项目中使用Less或者Sass等CSS预处理器可以更加简化代码的编写与计算量。
1 | //需要适配的设备宽度数组 |
生成的css为
1 | @media (min-width: 320px) { |
使用less维护起来就方便很多,只要维护adapterDeviceWidthList
中设备的宽度即可,如果设计稿开始有变化更改变量即可。