之前有尝试过使用flexible.js移动端适配的解决方案,当时并未理解到精髓,导致在最近的开发中,有点触碰到知识盲区的感觉,折腾了一阵子才整清楚。
基本概念
设备像素比(dpr) = 物理像素 / 设备独立像素
在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的
,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。
meta标签:<meta>
标签有很多种,而这里要着重说的是viewport的meta标签,其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。
rem:rem就是相对于根元素<html>
的font-size来做计算。
flexible原理
flexible:会在<html>
元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值。
在引入lib-flexible需要执行的JS之前,可以手动设置meta来控制dpr值
<meta name="flexible" content="initial-dpr=2" />
如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。
flexible的实质
- 动态改写
<meta>
标签 - 给
<html>
元素添加data-dpr属性,并且动态改写data-dpr的值 - 给
<html>
元素添加font-size属性,并且动态改写font-size的值
如何计算scale
scale = 1 / dpr
dpr = 1 / scale
flexiable具体逻辑
- 如果本身设置了viewport,则根据已有的meta设置比例
- 你也可以自定义
name = flexible
的meta,自己设置比例 dpr - 如果都没有则根据navigator属性自动设置,具体规则为
- ios根据
window.devicePixelRatio
设置dpr为1,2,3 - android 直接使用dpr=1
- ios根据
- 在HTML根标签上设置data-dpr
- 如果本身没有设置viewport,动态创建meta标签,并写入scale
- 根据实际宽度,动态设置html的font-size
- 移动设备的实际尺寸最大按640计算
- remUnit(rem基准值,即1rem为多少px,也就是HTML的font-size)为 width / 10
浏览器的缩放会影响 devicePixelRatio 的值
px转换成rem
如果设计稿是750px大小,目前Flexible会将视觉稿分成100份(主要为了以后能更好的兼容vh和vw),而每一份被称为一个单位a。同时1rem单位被认定为10a,<html>
对应的font-size为75px,具体的rem值 = 原始px值除以rem基准值即可。
1a = 7.5px
1rem = 75px
快速转换,利用工具:Sass、Less以及PostCSS这样的处理器。
字号不使用rem
经过flexible处理后的页面,你可以理解成一张照片,在大屏和小屏的显示是一致的。但有时候对于与段落文本,我们可能并不想这样,比如我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本。
如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]
属性来区分不同dpr下的文本字号大小。
div { width: 1rem; height: 0.4rem; font-size: 12px; // 默认写上dpr为1的fontSize }
[data-dpr="2"] div { font-size: 24px; }
[data-dpr="3"] div { font-size: 36px; }
为什么
记住一个约定:px2rem和fleiable都约定remUnit = width / 10
。
在设计稿上,假定我们设置A元素宽度为w1,总宽度为w0,则对应rem=w1/remUnit=10w1/w0
。
在真实设备上,假定总宽度为w2,则remUnit=w2/10
。
因此A元素在真实设备上宽度为:10w1 / w0 * w2 / 10 = w1 * w2/ w0
。这就说明了A元素的宽度会根据真实设备的宽度进行缩放。