惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
L
LINUX DO - 热门话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
V
V2EX
GbyAI
GbyAI
量子位
Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
S
SegmentFault 最新的问题
O
OpenAI News
N
News and Events Feed by Topic
博客园 - Franky
爱范儿
爱范儿
Forbes - Security
Forbes - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V2EX - 技术
V2EX - 技术
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
P
Privacy International News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
Last Week in AI
Last Week in AI
罗磊的独立博客
Spread Privacy
Spread Privacy
Recent Announcements
Recent Announcements
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
AWS News Blog
AWS News Blog
The Register - Security
The Register - Security
Y
Y Combinator Blog
J
Java Code Geeks
I
Intezer

Jay Zangwill

前端该如何选择图片的格式 扒一扒浏览器缓存机制 line-height和vertical-align采坑记 分享个人前端学习路线及面试经验 搜狗实习总结 vue-cli-multipage 记一次我看红宝书对继承加深的理解 四月北京面试之旅 常用的mongodb命令 几个让我印象深刻的面试题(二) 几个让我印象深刻的面试题(一) css盒模型与定位 javscript的数据类型 angular学习笔记(3) angular学习笔记(2) angular学习笔记(1) 初尝vue sass基础 hexo+github快速搭建个人博客
移动端适配
Jay Zangwill · 2019-04-02 · via Jay Zangwill

前言

原文 && 个人主页

知乎 && 知乎专栏

背景

随着移动端的普及,以及手机尺寸越来越多,这就衍生了众多的适配方案,以下挑一些常见的适配方案进行探讨。

本文默认读者已经对视口、物理像素、逻辑像素、css像素等移动端基本概念已经了解了。

px + viewport适配

这种适配方案原理比较简单:实际上就是通过动态设置meta标签的viewport让css中的1px等于设备的1px。

js伪代码:

1
2
3
4
5
const scale = 1 / devicePixelRatio

head.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伪代码

1
2
3
4
5
6
7
8
9
[data-dpr='3'] {
property: value * 3
...
}

[data-dpr='2'] {
property: value * 2
...
}

大家可以用不同手机进入这里,或者用浏览器模拟。

优点:简单易于理解

缺点:不能涵盖所有dpr的机型,即使能,也会造成代码臃肿。

rem布局

首先我们需要知道

  1. rem的大小是基于页面根元素的font-size
  2. 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伪代码:

1
html.fontSize = clientWidth / 750

你以为这就完事了?其实事情并没有那么简单。

表情

别忘了,平时我们开发都是在chrome下开发的。chrome并不支持font-size小于12的字体,那怎么办呢?

还能怎么办,为了方便计算,让font-size大于12呗,在以上基础上将结果放大100倍,然后写样式的时候再除以100:

表情

js伪代码:

1
html.fontSize = clientWidth / 750 * 100

样式:

1
2
3
.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布局的优缺点

优点: 易于理解,且兼容性好,能够很好地解决适配问题。

缺点:

  1. 需要用js额外设置字体大小,强制设置根元素的字体大小,剥夺了用户的自由
  2. 在webview中,部分机型下用户设置系统默认字体大小会造成布局错乱

小程序的黑魔法rpx布局

做过小程序的都知道,小程序有个wxss,这玩意有个rpx的单位,官方文档是这么介绍他的:可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素

再看到下面那个转换表时我瞬间就不淡定了:

rpx

既是根据屏幕宽度自适应的又和上一章讲到的:基于设计图的rem布局的换算结果一样的,那它内部的实现原理其实和基于设计图的rem布局的原理差不多。

只不过小程序内部处理了一下,让rpx直接能够根据屏幕宽度自适应,而不是像rem那样依赖于根元素的font-size

vw布局

上一章基于屏幕百分比的rem布局小节中提到的x代表1份屏幕的宽度,在css中刚好有个单位代表这个x,即vw,至于vw是啥这里就不多说了,都9012年了,竟然还不知道vw是什么,传送门

那么问题来了,平时我们拿到的设计图都是基于px标记的,怎么将px转为vw呢?

emmm,这里有个专门的插件专门做这件事postcss-px-to-viewport

其代码中有这么一句:

1
toFixed((pixels / viewportSize * 100), opts.unitPrecision)

是不是和我们上面所说的实际的rem = 元素标注长度 / 设计图宽度(这里是750) * 100很像?

这个插件会解析我们的css文件,将px转换为vw,至于为什么要这么转化,上面已经说过了,这里就不再赘述。

vw完美地避开了rem的缺点,还继承了rem的优点,然而vw并不是完美的,由于pxvw是经过js计算的,多少都会优些精度损失,不过这是个小问题,不会丢失多少精度,除非你对精度要求特别高。

参考

Rem布局的原理解析
rem, vw, 还是…? 各凭本事的移动端适配方案