前言
原文 && 个人主页
知乎&&知乎专栏
背景
随着移动端的普及,以及手机尺寸越来越多,这就衍生了众多的适配方案,以下挑一些常见的适配方案进行探讨。
本文默认读者已经对视口、物理像素、逻辑像素、css像素等移动端基本概念已经了解了。
px + viewport适配
这种适配方案原理比较简单:实际上就是通过动态设置meta
标签的viewport让css中的1px等于设备的1px。
js伪代码:
const scale = 1 / devicePixelRatiohead.appendChild(`<meta name='viewport' content='width=device-width, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable='no'>`)body.setAttribute('data-dpr', devicePixelRatio)
css伪代码
[data-dpr='3'] {property: value * 3...}[data-dpr='2'] {property: value * 2...}
大家可以用不同手机进入这里,或者用浏览器模拟。
优点:简单易于理解
缺点:不能涵盖所有dpr的机型,即使能,也会造成代码臃肿。
rem布局
首先我们需要知道
rem
的大小是基于页面根元素的font-size
。rem
的本质是等比缩放。
例如:根元素的font-size: 16px
则,1rem
就等于16px
;根元素的font-size:32px
则,1rem
就等于32px
可以到这里来意会一下rem
的本质是缩放
这么一来,我们就可以利用这个特性动态设置根元素的font-size
来达到我们想要的效果。
基于设计图的rem布局
通常我们拿到的设计图宽度的是750也就是基于iphone6/7/8的设计图,我们如果要想让1px像素等于设计图的1px该怎么做呢?
其实很简单,直接让根元素的font-size: 0.5px
即可(因为是2倍图,1px等于2实际像素,所以为0.5px
)。
那么问题来了:设计图一定会是750的,可是市面上机型那么多,屏幕不一定是750啊,怎么办?
前面我说过,rem的本质是等比缩放,让大于750或者小于750屏幕的手机等比缩放不就完事了?
js伪代码:
html.fontSize = clientWidth / 750
你以为这就完事了?其实事情并没有那么简单。
别忘了,平时我们开发都是在chrome下开发的。chrome并不支持font-size
小于12的字体,那怎么办呢?
还能怎么办,为了方便计算,让font-size
大于12呗,在以上基础上将结果放大100倍,然后写样式的时候再除以100:
js伪代码:
html.fontSize = clientWidth / 750 * 100
样式:
.element {width: 0.1rem; /* 实际到6/7/8上就是10px */}
基于屏幕百分比的rem布局
假设一个页面有100份,每一份的宽度用x
表示,则x=屏幕宽度(即clientWidth)/100
,如果font-size: x
,那我们不就实现了1rem === 1%
屏幕宽度了吗?
可是现实是残酷的,平时我们开发的时候写样式可不是按照屏幕宽度的百分之几来写的,而是根据设计给的标注来写的,而且设计通常给的设计图宽度是750
的,那么如何转换呢?
其实可以换种思维:如果得到这个元素的宽度占页面宽度的百分之几不就完事了吗?
所以,实际的rem = 元素标注长度 / 设计图宽度(这里是750) * 100
当然,这个转换过程可以让postcss去帮我们转换。
rem布局的优缺点
优点:易于理解,且兼容性好,能够很好地解决适配问题。
缺点:
需要用js额外设置字体大小,强制设置根元素的字体大小,剥夺了用户的自由在webview中,部分机型下用户设置系统默认字体大小会造成布局错乱
小程序的黑魔法rpx布局
做过小程序的都知道,小程序有个wxss
,这玩意有个rpx的单位,官方文档是这么介绍他的:可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素
再看到下面那个转换表时我瞬间就不淡定了:
既是根据屏幕宽度自适应的又和上一章讲到的:基于设计图的rem布局的换算结果一样的,那它内部的实现原理其实和基于设计图的rem布局的原理差不多。
只不过小程序内部处理了一下,让rpx直接能够根据屏幕宽度自适应,而不是像rem那样依赖于根元素的font-size
vw布局
上一章基于屏幕百分比的rem布局小节中提到的x
代表1份屏幕的宽度,在css中刚好有个单位代表这个x
,即vw,至于vw是啥这里就不多说了,都90了,竟然还不知道vw是什么,传送门。
那么问题来了,平时我们拿到的设计图都是基于px
标记的,怎么将px
转为vw
呢?
emmm,这里有个专门的插件专门做这件事postcss-px-to-viewport
其代码中有这么一句:
toFixed((pixels / viewportSize * 100), opts.unitPrecision)
是不是和我们上面所说的实际的rem = 元素标注长度 / 设计图宽度(这里是750) * 100
很像?
这个插件会解析我们的css文件,将px
转换为vw
,至于为什么要这么转化,上面已经说过了,这里就不再赘述。
vw
完美地避开了rem
的缺点,还继承了rem
的优点,然而vw
并不是完美的,由于px
转vw
是经过js计算的,多少都会优些精度损失,不过这是个小问题,不会丢失多少精度,除非你对精度要求特别高。
参考
Rem布局的原理解析
rem, vw, 还是…? 各凭本事的移动端适配方案
如果觉得《chrome 适配调试_移动端适配》对你有帮助,请点赞、收藏,并留下你的观点哦!