移动端前端适配方案总结
相关概念
在介绍各方案之前,先有必要了解一些必备的名词。
px
全称 pixel
,像素。一个像素就是计算机屏幕所能显示一种特定颜色的最小区域。屏幕上显示数据最基本的点,不是长度单位。 如果点很小,那画面就清晰,我们称它为“分辨率高”,反之,就是“分辨率低”。
ppi
全称 Pixels Per Inch
,屏幕像素密度。单位是 dpi
,表示的是每英寸所拥有的像素(Pixel
)数目。 越大屏幕越高清。
分辨率
屏幕分辨率确定计算机屏幕上显示多少信息的设置,以水平和垂直像素来衡量,iphone5 屏幕上垂直有 1136 个物理像素,水平有 640 个物理像素。查询设备的分辨率及 ppi
rem
相对长度单位。相对于根元素(即 html
元素)的 font-size
计算值的倍数。
em
相对长度单位。在 font-size
中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width
。
vw,vh
视窗宽度/高度的 1%
物理像素(设备像素)
设备屏幕上的实际像素。如 iphone6
宽为 750
。
设备独立像素(逻辑像素/css 像素)
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css
像素),然后由相关系统转换为物理像素。如 iphone6
为 375×667
。
设备像素比(device pixel ratio/屏幕分辩比/dpr)
设备像素比 = 物理像素 / 设备独立像素
在某一方向上,x
方向或者 y
方向。在控制台通过 window.devicePixelRatio
可得。
所以 iphone6
的 DPR
为 2。
scale
scale
是屏幕拉伸比。也就是视口上的 initial-scale
, maximum-sacle
等属性。
视口(viewport)
布局视口:网页在开始设计时候的
dom
宽度(比如960px
)可视视口:整个屏幕的视口(比如
iphone6
375px
)完美视口:
1
2
3
4
5
6
7
8<meta name="viewport" content="initial-scale=1.0,width=device-width,user-scalable=0,maximum-scale=1.0" />
<!--
width:设置布局视口的宽
init-scale:设置页面的初始缩放程度
minimum-scale:设置了页面最小缩放程度
maximum-scale:设置了页面最大缩放程度
user-scalable:是否允许用户对页面进行缩放操作
-->
目前主流的自适应布局解决方案
响应式(Responsive web design)
通过媒体查询根据不同的屏幕分辨率来进行适配。
优点:
media query
可以做到设备像素比的判断,方法简单,成本低,特别是对移动和PC
维护同一套代码的时候。目前像Bootstrap
等框架使用这种方式布局。- 图片便于修改,只需修改
css
文件。 - 调整屏幕宽度的时候不用刷新页面即可响应式展示。
缺点:
- 代码量比较大,维护不方便。
- 为了兼顾大屏幕或高清设备,会造成其他设备资源浪费,特别是加载图片资源。
- 为了兼顾移动端和
PC
端各自响应式的展示效果,难免会损失各自特有的交互方式。
流式布局
1 | <meta name="viewport" content="width=width=device-width,initial-scale=1,maximum-scale=1, minimum-scale=1,user-scalable=no" /> |
流式布局需要用到百分比
或者 flex
,即宽度永远铺满页面宽度,但高度和其他单位仍然用 px
。它的字体精度可以保持跟设备系统一致(dpi
)。
移动端 vw+rem 布局(主流)
在没有 vw
的上古时代,我们通常这样来设置根字体 font-size
的大小:
1 | (function () { |
通过屏幕尺寸发生变化就获取屏幕宽度的方式,动态获取计算根字体的大小。
如果支持 css vw
,则 1vw
本质即等于上文中 width/100
。则换算过来为 fontSize = (100vw/750) * 32
,且不需要运行 js
及监听,直接设置 css
为:
1 | html { |
然后启用 postcss
的 postcss-pxtorem
将其他元素的 px
转为 rem
:
1 | module.exports = { |
其中 rootValue
为默认的根字体尺寸,通过 pxtorem
确定了其他元素尺寸与根元素尺寸固定的比例对应关系。
scale 伸缩布局
视觉稿、页面宽度、viewport width
使用统一宽度,利用浏览器自身缩放完成适配。页面样式(包括图像元素)完全按照视觉稿的尺寸,使用定值单位 (px、em
)即可完成。
法一
通过 js
更改 viewport
的 initial-scale
。
法二
写死 viewport
的宽度.
1 | <meta name="viewport" content="width=360, user-scalable=no" /> |
优点:
- 开发简单:缩放交给浏览器,完全按视觉稿切图。
- 还原精准:绝对等比例缩放,可以精准还原视觉稿(不考虑清晰度的情况下)。
- 测试方便:在
PC
端即可完成大部分测试,手机端只需酌情调整一些细节(比如图标、字体混合排列时,因为字体不同造成的对齐问题)。
缺点:
- 像素丢失:对于一些分辨率较低的手机,可能设备像素还未达到指定的
viewport
宽度,此时屏幕的渲染可能就不准确了。比较常见的是边框“消失”了,不过随着手机硬件的更新,这个问题会越来越少的。 - 缩放失效:某些安卓机不能正常的根据
meta
标签中width
的值来缩放viewport
,需要配合initial-scale
。 - 文本折行:存在于缩放失效的机型中,某些手机为了便于文本的阅读,在文本到达
viewport
边缘(非元素容器的边缘)时即进行折行,而当viewport
宽度被修正后,浏览器并没有正确的重绘,所以就发现文本没有占满整行。一些常用的段落性文本标签会存在该问题。 - 不能开启
gpu raster
硬件加速:不能显式设置minimum-scale=1.0
,否则就达不到效果。而这个值是chromium37
以上的webview
触发gpu raster
的一个条件,所以用这种方法就没法利用gpu raster
硬件加速。
注:
其他
PX 适配
在新闻,社区等可阅读内容较多的场景直接使用 px
单位可以营造更好地体验。px
方案可以让大屏幕手机展示出更多的内容,更符合人们的阅读习惯。就无需 rem
来等比缩放。
- 新闻,社区等可阅读内容较多的场景:
px+flex+百分比
- 对视觉组件种类较多,视觉设计对元素位置的相对关系依赖较强的移动端页面:
vw + rem
retina 下图片高清方案
- 两倍图片(
@2x
),然后图片容器缩小50%
(方便但会造成资源浪费)。 - 不同的
dpr
下,加载不同的尺寸的图片。
retina 下 1px 解决方案
对于一条 1px 宽的直线,它们在屏幕上的物理尺寸是相同的,不同的其实是屏幕上最小的物理显示单元,即物理像素。所以对于一条直线,iphone6
它能显示的最小宽度用 css
来表示,理论上说是 0.5px。
所以,设计师想要的 retina 下 border: 1px;
,其实就是 1 物理像素宽,对于 css 而言,可以认为是 border: 0.5px;
,这是 retina 下(dpr=2
)下能显示的最小单位。
元素 scale
(方便但圆角等无法用)
1 | .scale { |
判断添加 class
js
来判断当前浏览器是否支持 border
的 0.5px,如果支持就会在 HTML
上添加一个 class
名 hairlines
。
1 | if (window.devicePixelRatio && devicePixelRatio >= 2) { |
1 | div { |
注:3 倍屏下,不是 0.3333px?在 Chrome 上模拟 iPhone 8Plus,小于 0.46px 时无法显示。
设置 viewport 的 scale 值(不推荐)
1 | var viewport = document.querySelector('meta[name=viewport]'); |
因为涉及到所有的尺寸都要调整,且其他第三方组件不一定适配。
其他方式
- 使用边框图片
- 使用
box-shadow
实现:box-shadow: inset 0px -1px 1px -1px #d4d6d7
;