移动端适配(mobile terminal adaptation)
前言
目前移动端的屏幕大小各异,市面上各种尺寸的机型都有,而且有 1 倍屏,2 倍屏,3 倍屏之分,这对前端界面在不同设备下的呈现效果提出挑战,我们希望找到一种完美适配各种机型的方案(元素和字体能够保持一定比例随着用户屏幕尺寸变化),在用户面前呈现想要的效果。下面这篇文章聊聊关于前端开发中移动端适配的问题。
几个基本概念
屏幕大小
屏幕对角的的长度。1 英寸 = 2.54 厘米,那么一个 5 寸的手机的对角线长度就是 5 X 2.54 = 12.7
厘米。
分辨率
屏幕的像素点个数,例如:一个屏幕的分辨率为 320 * 480
即这个屏幕上有 320 X 480
个像素点。
px(pixels)
1px = 1inch * 1/96
(在一臂观察距离下,20inch)。 px 像素是 Web 开发中常用的单位。 1px 代表屏幕上一个物理像素点,在不同分辨率的设备上像素点的大小不同,同尺寸的屏幕分辨率越高,像素点越小,反之越大。
pt(point)
是一个标准的长度单位,1pt = 1 / 72英寸
, ios 开发使用的单位。 pt 同时也是印刷行业常用单位,能够使用测量设备测得的长度。
ppi(pixels per inch)
即像素密度,它标志每英寸屏幕上有多少个设备像素点,ppi 越大,屏幕的分辨率越高,显示画面细节越丰富。计算公式为:$\frac{\sqrt{(W^2+H^2)}}{S}$,其中 W 和 H 是分辨率的宽高, S 是屏幕尺寸。
dpi(dot per inch)
dpi 和 ppi 的概念相似,指打印设备每英寸印刷出来的点
有多少个,值越高,图片越细腻。
dip(device independent pixels)
dp ,是设备独立像素,也叫逻辑像素,又称密度无关像素。它是一个逻辑单位,即无论图形在屏幕上如何缩放,它们始终都有一个不变的逻辑尺寸。不同坐标系或不同系统,会有自己对应的设备独立像素。
dpr(devicePixelRatio)
设备物理像素和设备独立像素比,即$dpr =\frac{物理像素}{css像素}$是指在理想布局宽度,使用多少个物理像素来渲染一个 css 像素。 dpr 越高,屏幕的单位尺寸内设备像素越多,显示内容越细腻。
相关获取
- 屏幕的设备独立宽度
1 | const dipWidth = screen.width; |
- 屏幕的设备独立宽度
1 | const dipHight = screen.height; |
- dpr
1 | const dpr = window.devicePixelRatio; |
- 物理像素宽度
1 | const physicalWidth = dipWidth \* dpr; |
css 中,通过 css 中通过-webkit-device-pixel-ratio
,-webkit-min-device-pixel-ratio
,-webkit-max-device-pixel-ratio
进行媒体查询。
- 物理像素高度
1 | const physicalHight = dipHeight * dpr; |
关于视口(viewport)
移动端涉及布局视口(Layout Viewport)、视觉视口(Visual ViewPort)和理想视口(Ideal ViewPort)。
- 布局视口(layout viewport): 用于网⻚的布局。可以看作是 html 元素的上一级容器即顶级容器,默认情况或者将 html 元素的 width 属性设为 100% 时,会占满这个顶级容器,此时用
document.documentElement.clientWidth
获取到 html 元素的布局宽度也就是布局视口的宽度,使用媒体查询时 max-width 和 min-width 的值指的也是布局视口的宽。无论移动端浏览器是否进行了缩放、横纵切换,在⻚面初始化后,这个视口的大小将固定不变。
layout viewport 并不是整个网⻚内容,它只是移动端适配手机小屏的逻辑视口。布局视口的高度并不等于整个网⻚的高度,同时 position: fixed 的定位是基于布局视口的。
- 可视视口(visual viewport): 用于展示当前屏幕内容。滑动屏幕、横纵切换、缩放操作等,实际上都是对可视视口的操作。
相关操作:滑动⻚面 -> 移动 visual viewport 的坐标;缩放⻚面 -> 修改 visual viewport 的宽高;横纵屏切换 -> 调换 visual viewport 的宽高,并映射。
- 理想视口(Ideal ViewPort): 是屏幕分辨率的值,即对设备来说是最理想的布局视口,用户不需要对页面进行缩放就能完美的显示整个页面。最简单的做法就是使布局视口宽度设置为手机屏幕的宽度。通过设置
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
实现。
关于<meta>
标签
<meta>
标签中定义了一些元数据信息,通过设置<meta name = "viewport">
,提供有关视口初始大小的信息,供移动设备使用。属性值为:
属性 | 属性值 | 描述 |
---|---|---|
width |
数值 / device-width |
视口宽度 |
height |
数值 / device-height |
视口高度 |
initial-scale |
0.0 ~ 10.0 | 设备宽度与视口大小间缩放比例(初始值) |
maximum-scale |
0.0 ~ 10.0 | 缩放最大值 |
minimum-scale |
0.0 ~ 10.0 | 缩放最小值 |
user-scalable |
Boolean 类型 | 能否缩放页面,默认yes|1 |
适配方案
多媒体查询@media
多媒体查询@media
:通过给不同分辨率的设备编写不同的样式实现响应式布局,解决不同设备不同分辨率之间的兼容,一般是 PC、平板、手机设备之间较大的分辨率差异。优点是能够实现不仅仅是样式伸缩变换的样式改变。缺点是要匹配足够多的设备与屏幕,工作量大;达到断点变化明显,用户体验不好。
1 | // 屏幕可视窗口尺寸小于 480 像素时 font-size: 16px |
vw、vh、vmin、vmax
vw、vh、vmin、vmax
:vw
:是 viewport width 的简写,是可视区域尺寸的相对单位,1vw 相当于 1% 的可视区域的宽度;vh
: 是 viewport height 的简写,是可视区域尺寸的相对单位, 1vh 相当于 1% 的可视区域的高度;vmin
: 当前 vh 和 vw 的最小值;vmax
:当前 vh 和 vw 的最大值。使得元素能够随视口大小自适应调整,是纯 css 移动端适配方案,不存在脚本依赖问题。但是存在一些兼容性问题,在 Android 4.4 / iOS 8 以下不支持。
rem
rem
:rem 是相对长度单位, rem 方案中的样式设计为相对于根元素(html) font-size 计算值的倍数。在布局时使用 rem 单位布局,达到自适应的目的,实现弹性布局。但是 rem 布局存在以下问题:不是纯 css 移动适配方案,需要引入 js 脚本 在头部内嵌一段 js 脚本监听分辨率的变化来动态改变根元素的字体大小,css 样式和 js 代码有一定耦合,并且必须将改变 font-size 的代码放在 css 样式前。同时浏览器渲染最小单位是像素,元素根据屏幕宽度自适应,通过 rem 计算后可能会出现小数像素,浏览器会对这部分小数四舍五入,按照整数渲染。会出现小数像素的问题,我们可以指定最小转换像素,对于比较小的像素,不转换为 rem 或 vw 解决。
1 | document.documentElement.style.fontSize = |
通过@media 改变 font-size 值,和使用 vw / wh 设置 font-size 的大小同样可以改变上面讲到的 rem 相对长度
px 自动转换为 vw
px自动转换为vw
:设计师一般给宽度大小为 750px 的视觉稿,我们采用 vw 方案的话,需要将对应的元素大小单位 px 转换为 vw 单位,这是一项影响开发效率(需要手动计算将 px 转换为 vw)且不利于后续代码维护的工作。这时可以使用 postcss-px-to-viewport 插件,将 px 自动转换为 vw。
一些适配问题
- 1px 的问题:1 px 问题指的是在视觉设计师眼里的 1px 是指设备像素 1px,而如果我们直接写 css 的大小 1px,那在 dpr = 2 时,则等于 2px 设备像素,dpr = 3 时,等于 3px 设备像素。所以对于要求处理 1px 的场景,我们要进行特殊处理。
1 | // 解决方案,使用 transform: scale(0.5) + :before / :after |
- 图片高清的问题:适用普通屏的图片在高清屏中展示模糊,适用高清屏的图片在普通屏中,展示缺少色差、没有锐利度,并且浪费带宽。
1 | /* 解决方案,对不同 dpr 屏幕使用不同 image 图片 */ |