面向场景:移动端 Web 页面,需要全局适配各种不同分辨率的的手机。
基本概念
- 物理像素(physical pixel):
物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。
屏幕可视宽为 320 像素,非 retina 屏的 pp 是 320,retina 屏的则至少为 640。
- 设备独立像素(density-independent pixel):
设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说 CSS 像素),然后由相关系统转换为物理像素。
dip 是个虚拟单位,在 web 世界中也称为 css 像素[逻辑像素],屏幕可视宽为 320 像素,dip 也就是 320 像素 。
- 设备像素比(device pixel ratio)
设备像素比简称为 dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:
1 | 设备像素比 = 物理像素 / 设备独立像素 // 在某一方向上,x方向或者y方向 |
在 JavaScript 中,可以通过 window.devicePixelRatio 获取到当前设备的 dpr。而在 CSS 中,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio 和 -webkit-max-device-pixel-ratio 进行媒体查询,对不同 dpr 的设备,做一些样式适配(这里只针对 webkit 内核的浏览器和 webview)。
- 屏幕尺寸:
屏幕尺寸是以屏幕对角线的长度来计量,计量单位为英寸。
例如,iPhone 5 是 4 英寸,iPhone6 是 4.7 英寸,指的是显示屏对角线的长度(diagonal)。
- 屏幕比例
屏幕比例不是固定的,常见比例是 4:3、16:9,所以长和宽的尺寸是不固定的。
例如,iPhone 5 是 4:3,iPhone 6 是 16:9,现在流行的全面屏大多是 18:9。
部分机型示例
机型 | iPhone 5/SE | iPhone 6/7/8 | iPhone 6/7/8 Plus |
---|---|---|---|
设备分辨率代表物理像素(pixel) | 640×1136 | 750×1334 | 1080×1920(开发时应按照 1242x2208) |
逻辑分辨率代表独立像素(point) | 320×568 | 375×678 | 414×736 |
设备像素比(dpr) | 2 | 2 | 3 |
相关 JS Web API
1 | window.devicePixelRatio // 设备像素比dpr |
适配方案
参考淘宝的 flexible.js 修改(目前使用)
在入口页面的 head 标签内中添加以下代码
1 | <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> |
这里我们使用的设计稿尺寸是以 750px 为基础设计的,所以要把视觉稿中的 px 转换成 rem
rem计算方式:设计图尺寸px / 100 = 实际rem 【例: 100px = 1rem,50px = 0.50rem】;
使用postcss-pxtorem,自动将 px 转为 rem,灰常便利
1 | // px单位大写将忽略转化rem,例如border-width: 2PX; // ignored |
Tips
- 淘宝那边的适配方案,不推荐用 rem 作为文本字体大小单位。所以对于字体的设置,仍旧使用 px 作为单位,并配合用 data-dpr 属性来区分不同 dpr 下的的大小
来自淘宝 lib-flexible:现在绝大多数的字体文件都自带一些点阵尺寸,通常是 16px 和 24px,所以我们不希望出现 13px 和 15px 这样的奇葩尺寸。
来自淘宝 lib-flexible:“针对 OS 9_3 的 UA,做临时处理,强制 dpr 为 1,即 scale 也为 1,虽然牺牲了这些版本上的高清方案,但是也只能这么处理了”;
所以我们干脆直接对所有字体大小使用 px 作为单位来定义,放弃 data-dpr 标识的区分,很鸡肋。(个人推荐用的 px 做字体单位)
- 一些不推荐使用 rem 的 CSS 属性:border-width、border-radius、box-shadow、transform、background-size
- 注意只有当你需要某元素的单位要根据屏幕宽度大小变化时,才需要 rem、em 这类动态宽度单位。一般情况下字体大小是没必要根据屏幕宽度变化
使用 vw,viewport 单位,表示将屏幕均分 100 份,1vw 就是 1 份(以后要流行的方案)
去参考下手淘(作者)分享的解决方案
如何在 Vue 项目中使用 vw 实现移动端适配
使用媒体查询(@media screen)
- 设计图尺寸:750x1334 px
- rem 计算方式:设计图尺寸 px / 100 = 实际 rem 【例: 100px = 1rem,50px = 0.50rem】
在模板页面的 css 中添加以下代码
1 | html{ |
其他
处理 1 像素边框
在 rem 方案中,如果没有特殊处理,1px 的线条在 dpr 大于 1 的设备会比较粗。根本原因是 1px 可能会占用两个物理像素点或以上。
可以采用 transform: scale(0.5);来解决,在上面的selectorBlackList
添加'.ui-hairline'
1 | .ui-hairline, .ui-hairline--bottom, .ui-hairline--left, .ui-hairline--right, .ui-hairline--surround, .ui-hairline--top, .ui-hairline--top-bottom { |
获取手机设备系统信息
1 | var util = { |
util.getSystemInfo()
返回参数说明
属性 | 类型 | 说明 |
---|---|---|
userAgent | String | 用户代理,简称 UA |
platform | String | 客户端平台:Android,iOS |
pixelRatio | Number | 设备像素比 |
screenWidth | Number | 屏幕宽度,单位 px |
screenHeight | Number | 屏幕高度,单位 px |
windowWidth | Number | 可使用窗口宽度,单位 px |
windowHeight | Number | 可使用窗口高度,单位 px |
language | String | 语言 |
Tips
userAgent
其实里面包含更多信息,例如手机型号,系统版本,
1 | // 小米note3(手机型号:Mi Note 3,系统版本:Android 9) |
不难发现,在 UA 中,可以看待安卓的手机型号一般在Build/
前面,ios 的还并没有发现