关于移动端适配的一些问题(笔记)
关于移动端适配的一些问题(笔记)
镇长原文 《关于移动端适配,你必须要知道的》 - code秘密花园
前言
移动端适配,经常遇到的问题。首先要分清 设备独立像素、CSS像素、DPR、PPI、DIP 概念和区别。
- 基础概念
- 字体大小区别
- 1px 问题
- UI 图完美适配方案
- iPhoneX 适配方案
- 横屏适配
- 高清屏图片模糊的问题
- …
理解问题产生的原因,可以更好的解决问题。
一、基本概念
1.1 英寸(inch)
一般用英寸来描述屏幕的大小,如手机 5.7、6.5 等使用的单位都是英寸。
屏幕的尺寸指定是对角线的长度。
1.2 分辨率
分辨率一般分为两种:屏幕分辨率和图片分辨率。
屏幕分辨率是指一块屏幕上有多少个像素点。如:iPhone 11 Max Pro
的分辨率是 2688 x 1242
,表示的是屏幕在水平和垂直方向上像素点数。
图像分辨率是指图片含有的像素数,比如一张分辨率为 1080*768
,表示图片在垂直和水平方向上所具备的像素点数。
1.3 每英寸像素(PPI)
PPI
表示每英寸中像素的数目,确切的说是像素密度,对于屏幕来说是指每英寸物理像素的数目及显示器设备的点距。数值越高,代表显示器的显示密度越高。
1 | PPI = \frac{\sqrt{水平像素点数^2+垂直像素点数^2}}{尺寸} |
以 iPhone 11 Max pro
为例。
1 | \frac{\sqrt{2688^2+1242^2}}{6.5} ≈ 455 |
那么屏幕每英寸约有 455 个物理像素点。实际尺寸不到6.5。
1.4 DPI
DPI:每英寸包含的点数,是一个抽象单位,可以是屏幕像素点、图片像素点也可以是打印机墨点。当 DPI 描述屏幕和图片时与 PPI 等价。
1.5 设备独立像素(DIP)
设备独立像素,也称为逻辑像素,简称 DIP。
用来告诉不同分辨率的手机,它们在界面上显示元素的大小是多少。
1.6 设备像素(DP)
设备像素(Device Pixels,px),又称为物理像素,是指显示屏上的一个个物理点。物理像素的点大小是固定的,单位是pt
。每块屏幕的物理像素多少在出厂时已经确定。pt
在 CSS
单位中属于真正的绝对单位。1pt = 1/72(inch)
一英寸等于2.54厘米。例如:iPhone 11 Max pro 2688 x 1242 像素分辨率,458 ppi
1.7 CSS像素(PX)
CSS像素 (CSS Pixel, px),又称为虚拟像素。就是Web
中使用的像素,单位是 px
。 在 CSS
规范中,长度分为两类,绝度单位和相对单位。这里 px
是一个相对单位,相对的是设备像素。
CSS像素是图像显示的基本单元,是一个相对量,是一个抽象的概念。所以在说CSS像素大小的时候要考虑上下文的不同。
由于不同的设备的物理像素是不同的,所以 CSS 认为浏览器会对 CSS 中的像素进行调节,使得浏览器中 1 CSS 像素的大小在不同的设备上看起来差不多,目的是为了保证阅读体验。
在 DPR 为 1的屏幕中,浏览器可视窗口 800px 里面有个 div 为 400px ,此时将页面放大 200%,发现 div 宽度占满这个浏览器。也就是说默认一个 CSS 像素等于一个物理像素宽度,放大后一个CSS像素等于两个物理像素宽度。所以,可以看出 CSS 像素是一个相对值。
1.8 设备像素比 (DPR)
在为缩放状态下,设备像素和CSS像素之间的比例关系。苹果的 Retina
屏的DPR为2,也就是说2*2个物理像素表示一个CSS像素。
在 web 中,浏览器通过 window.devicePixelRatio
来获取 DPR。
在 CSS 中,使用媒体查询min-device-pixel-ratio
,区分 DPR。
1 | @media (-webkit-min-device-pixel-ratio:2),(min-device-pixel-ratio:2){} |
换算关系
1 | DPR = \frac{设备像素}{设备独立像素} |
二、设备独立像素(DIP)
在 iOS 、Android 和 ReactNative
中使用的都是设备独立像素。
iOS
单位为 pt
;Android
单位为 dp
;ReactNative
未指明其实也是设备独立像素dp
。
为了适配屏幕,需要将物理像素转为设备独立像素。例如:给定一个元素的高度 200px (此时px表示物理像素而不是CSS像素),iPhone 6
的设备像素比为2,那么给定的元素高度应该是 200px/2 = 100dp
。
在 Web 开发中,使用的是CSS像素,当页面的缩放比为100%时,一个CSS像素等于一个设备独立像素。
当页面放大是,CSS像素也会被放大,一个CSS像素跨越多个设备独立像素。
1 | 页面缩放比 = \frac{CSS像素}{设备独立像素} |
经常用 P 和 K 描述屏幕。
P代表的是屏幕纵向的像素个数,1080p
即纵向上有1080个像素点,分辨率为 1920 * 1080
的屏幕就属于 1080P
屏幕。
K代表屏幕横向有几个1024个像素,一般来将横向屏幕超过 2048 就属于 2K 屏,超过 4096
就属于 4K 屏。
三、视口
视口( viewport)代表当前可见的计算机图形区域。在 Web浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的 UI, 菜单栏等——即指你正在浏览的文档的那一部分。
一般我们所说的视口共包括三种:布局视口、视觉视口和理想视口,它们在屏幕适配中起着非常重要的作用。
- 布局视口:是网页布局的基准窗口。
- 视觉视口:用户在屏幕中真是看到的窗口。
- 理想视口:网页在移动展示的理性大小。
Meta Viewport
借助 元素的 viewport来帮助我们设置视口、缩放等,从而让移动端得到更好的展示效果.
1 | <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"> |
看一下 viewport
的配置含义。
名称 | 可选值 | 描述 |
---|---|---|
width | 正整数、device-width | 定义布局视口的宽度,单位px |
height | 正整数、device-height | 定义布局视口的高度,单位px |
inital-scale | 0 - 10.0 | 定义页面初始缩放比率 |
minimum-scale | 0-10.0 | 定义缩放的最小值,必须小于或等于maximum-scale |
maximum-scale | 0-10.0 | 定义缩放的最大值 |
user-scalable | yes、no | 是否允许缩放 |
viewport-fit | contain、cover | 适配iphoneX等屏幕 |
移动适配,为了使页面获得更好的显示效果,让布局视口、视觉视口尽可能等于理想视口。
device-width 就是等于理想视口的宽度。由于 inital-scale=理性视口宽度/视觉视口宽度
,所以 initial-scale=1
时,理性视口等于视觉视口。
这是,一个 CSS像素等于一个设备独立像素,且是基于理想视口布局的,所以呈现出的效果在各设备上大致相似。
四、字体大小 px、em、rem、pt
4.1 px
回忆一下 px 像素是相对值,相对于屏幕的分辨率而言的。
1px是多少物理像素呢?需要先知道每英寸像素数DPI,Windows
默认是 96dpi,Apple
默认是 72dpi。
任意的浏览器的默认字体是 16px。
单位换算,默认情况下 16px = 1em = 1rem。
4.2 em
em
是指相对于父元素的字体大小的单位。相对字符宽度的倍数,类似于百分比。浏览器默认 1em = 16px。
默认浏览器符合:16px = 1em,12px = 0.75em, 10px = 0.625em。如设置 body 选择器的 font-size=62.5%,使1em = 10px, 1.2em = 12px。这样方便计算。
4.3 rem
rem 是相对于根元素的字体大小的单位,它是CSS3新增的相对单位。与 em 的区别在于前者相对父元素字体大小后者相对根元素自字体大小。
单位换算,根元素字体16px: 16px = 1rem;16px * 0.75 = 12px => 0.75rem = 12px。
4.4 pt
pt(磅): 是一个物理长度单位,指1/72英寸。
pt = 1/72(英寸),px = 1/dpi(英寸) => pt = px * 72/dpi
在 windows 下以96dpi来计算,pt = px * 72/96 = px * 3/4 及默认 16px = 12pt。
五、1px 边框问题
为了适配屏幕使用设备独立像素来对页面布局。在DPR大于1的屏幕上,1px实际上被多个物理像素渲染,这就出现 1px 在屏幕上看起来很粗的原因。
5.1 border-image
基于 media
查询判断不同的 DPR 给定不同的 border-image
。
1 | .border_1px { |
5.2 background-image
同 border-image
类似,将图片放在背景上。
1 | .border_1px { |
上面两种缺点是无法添加圆角。
5.3 伪类 + transform
基于 media 获取 DPR 对线条缩放。
1 | .border_1px:before { |
可以添加圆角,只需为伪类添加 border-radius
即可。
5.4 svg
借助 PostCSS
的 postcss-write-svg
直接使用 border-image 和 background-image 创建 svg 的 1px 边框。
1 | @svg border_1px { |
推荐使用这种方法。
六、适配iPhoneX屏幕
iPhoneX 出现取消了物理按键,改成了底部的小黑条,但是这样的改动给前端适配增加了难度。
6.1 安全区域
iPhoneX屏幕外观三个改动:圆角、刘海和小黑条。为了适配诞生了安全区域的概念,它是一个不受上面三个改动的影响的可视窗口。
6.2 viewport-fit
前面 viewport 中有个 viewport-fit=cover
,这个属性专门为 iPhoneX 诞生的属性,用于限制网页如何在安全区域内展示。
- contain: 可视窗口完全包含网页内容
- cover:网页内容完全覆盖可视窗口
默认情况下或者设置为 auto 和 contain效果相同。
6.3 env 和 constant
我们需要将顶部和底部合理的摆放在安全区域内, iOS11新增了两个 CSS函数 env、constant,用于设定安全区域与边界的距离。
函数内部可以是四个常量:
- safe-area-inset-left:安全区域距离左边边界距离
- safe-area-inset-right:安全区域距离右边边界距离
- safe-area-inset-top:安全区域距离顶部边界距离
- safe-area-inset-bottom:安全区域距离底部边界距离
注意:我们必须指定 viweport-fit
后才能使用这两个函数:
1 | <meta name="viewport" content="viewport-fit=cover"> |
constant在 iOS<11.2
的版本中生效, env在 iOS>=11.2
的版本中生效,这意味着我们往往要同时设置他们,将页面限制在安全区域内:
1 | body { |
七、横竖屏适配的问题
7.1 JavaScript 检测横竖屏
window.orientation:获取屏幕旋转方向
1 | window.addEventListener('resize', () => { |
7.2 CSS检测横屏
1 | @media screen and (orientation: portrait) { |
八、图片模糊问题
8.1 原因
平时使用的图片大多数属于位图(.png, jpg…),位图是由一个个像素点构成的,每个像素点具有特定的位置和色值。
理论上,一个像素点有一个物理像素点渲染效果最佳。但是在 dpr > 1
的屏幕中,一个位图像素点由多个物理像素点渲染,这些物理像素点不能准确的分配颜色,只能去近似值,所以相同的图片在 dpr > 1
的屏幕上模糊了。
8.2 解决方案
为了保证图片质量,可以在不同的 DPR 屏幕中显示不同分辨率的图片。
如:DPR = 2
的屏幕显示二倍图(@2x),在DPR = 3
的屏幕中显示三倍图(@3x)。
8.3 media 查询
使用 media
查询来判断不同的 DPR
来显示不同的背景图片。
1 | .avatar { |
这种方式只适用于背景图
8.4 image-set
1 | .avatar { |
这种方式只适用于背景图
8.5 srcset
使用 img
标签的 srcset
属性,浏览器会自动根据像素密度匹配最佳图片显示。
1 | <img src="xxx.png" srcset="xxx_2x.png 2x, xxx_3x.png 3x"> |
8.5 JS拼接图片 url
使用 window.devicePixelRatio 获取 DPR,遍历所有图片,替换图片地址。
1 | const dpr = window.devicePixelRatio |
9.6 使用 svg
SVG的全称是可缩放矢量图。不同于位图使用像素,SVG使用向量描述图片。它无论如何缩放都不会失真。除了用代码绘制 svg ,还可以像使用位图一样使用 svg 图片。