移动端适配

6/3/2020 h5

# 为什么要移动端适配

一般情况下设计稿的设计师按照375的尺寸设计,然而,在现在移动终端(就是手机)快速更新的时代,每个品牌的手机都有着不同的物理分辨率,这样就会导致,每台设备的逻辑分辨率也不尽相同,此时357的设计稿,如果想要还原那基本是不可能了,因为如果一个左右布局,左边如果写死,右边自适应的话,每个设备的右边所展示的内容大小就不尽相同,这是移动端适配就显得尤其重要

而要解决移动端适配,就需要了解屏幕尺寸、像素、分辨率、PPI、DPI、DP、DIP、DPR、视口等等这些概念。

# 屏幕尺寸

一般用英寸描述屏幕的物理大小,如电脑显示器的17、22,手机显示器的4.8、5.7等使用的单位都是英寸。

需要注意的是,以上尺寸都是屏幕的对角线的长度
1

英寸(inch,缩写为in)在荷兰语中的本意是大拇指,一英寸就是指甲底部普通人拇指的宽度。

英寸和厘米的换算:1英寸 = 2.54 厘米

# 分辨率

# 像素

像素就是一个具有特定的位置和颜色的小方块

图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。

像素可以作为图片或电子屏幕的最小组成单位。

# 什么叫分辨率呢?

屏幕分辨率是指纵横向上的像素点数,单位是px。屏幕分辨率确定计算机屏幕上显示多少信息的设置,以水平和垂直像素来衡量。就相同大小的屏幕而言,当屏幕分辨率低时(例如 640 x 480),在屏幕上显示的像素少,单个像素尺寸比较大。屏幕分辨率高时(例如 1600 x 1200),在屏幕上显示的像素多,单个像素尺寸比较小。

# 设备物理分辨率(设备像素)

从我们以前用的蓝屏机到彩屏手机再到现在的智能机,我们的我们的手越来越清晰,越来越大,所以我们的屏幕发展也越来越迅速。 上图可以清楚的看到,不同分辨率所带来的的差距 从最初的颗粒感相当大的屏幕,到720p再到1080p,甚至于现在各家旗舰手机的2k屏幕,我们的物理分辨率在变得原来越大。这样就暴露出来一个问题,我们如果手机分辨率翻倍,我们的图像不就要被缩小一倍,我们难道要在每个设备上就出个设计稿,每个设备的分辨不尽相同啊,其实你担忧的问题,我们的乔帮主在很多年前就想到了。这就是我们的逻辑分辨率

# 逻辑分辨率(设备独立像素)

我们现在使用的智能手机,不管分辨率多高,他们所展示的界面比例都是基本类似的。乔布斯在iPhone4的发布会上首次提出了Retina Display(视网膜屏幕)的概念。

在iPhone4使用的视网膜屏幕中,把2x2个像素当1个像素使用,这样让屏幕看起来更精致,但是元素的大小却不会改变。从此以后高分辨率的设备,多了一个逻辑像素。这些设备逻辑像素的差别虽然不会跨度很大,但是仍然有点差别,于是便诞生了移动端页面需要适配这个问题,既然逻辑像素由物理像素得来,那他们就会有一个像素比值

# 设备像素比 dpr

设备像素比device pixel ratio简称dpr,即物理像素和设备独立像素的比值

在web中,浏览器为我们提供了window.devicePixelRatio来帮助我们获取dpr。 在css中,可以使用媒体查询min-device-pixel-ratio,区分dpr: @media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ } 复制代码在React Native中,我们也可以使用PixelRatio.get()来获取DPR。 当然,上面的规则也有例外,iPhone 6、7、8 Plus的实际物理像素是1080 x 1920,在开发者工具中我们可以看到:它的设备独立像素是414 x 736,设备像素比为3,设备独立像素和设备像素比的乘积并不等于1080 x 1920,而是等于1242 x 2208。 实际上,手机会自动把1242 x 2208个像素点塞进1080 * 1920个物理像素点来渲染,我们不用关心这个过程,而1242 x 2208被称为屏幕的设计像素。我们开发过程中也是以这个设计像素为准。

# 适配

# 1px边框问题

当我们css里写的1px的时候,由于它是逻辑像素,导致我们的逻辑像素根据这个设备像素比(dpr)去映射到设备上就为2px,或者3px,由于每个设备的屏幕尺寸不一样,就导致每个物理像素渲染出来的大小也不同(记得上面的知识点吗,设备的像素大小是不固定的),这样如果在尺寸比较大的设备上,1px渲染出来的样子相当的粗矿,这就是经典的一像素边框问题
1

如何解决

transform: scale() 方案 可以利用css根据设备像素比媒体查询后,区分dpr,决定缩小2或者3倍

div {
    height:1px;
    background:#000;
    -webkit-transform: scaleY(0.5);// scaleY(0.33);
    -webkit-transform-origin:0 0;
    overflow: hidden;
}
1
2
3
4
5
6
7

# 常用移动端适配方案

# viewport

在移动端适配视口时,通常通过添加一个 meta 标签解决

<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
1

具体含义: 我们在移动端视口要想视觉效果和体验好,那么我们的视口宽度必去无限接近理想视口

理想视口:一般来讲,这个视口其实不是真是存在的,它对设备来说是一个最理想布局视口尺寸,在用户不进行手动缩放的情况下,可以将页面理想地展示。那么所谓的理想宽度就是浏览器(屏幕)的宽度了。

于是上述的meta设置,就是我们的理想设置,他规定了我们的视口宽度为屏幕宽度,初始缩放比例为1,就是初始时候我们的视觉视口就是理想视口!

# rem 适配

rem是CSS3新增的一个相对单位,他是相对于根元素(html元素)的font-size

提到rem 布局,就不得不提flexible,flexible方案是阿里早期开源的一个移动端适配解决方案,引用flexible后,我们在页面上统一使用rem来布局。

他的核心代码为:

// set 1rem = viewWidth / 10
function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
}
setRemUnit();
1
2
3
4
5
6

rem 是相对于html节点的font-size来做计算的。所以在页面初始话的时候给根元素设置一个font-size,接下来的元素就根据rem来布局,这样就可以保证在页面大小变化时,布局可以自适应,

如此我们只需要将UI出的图转换为rem即可。

以iPhone6为例:布局视口为375px,则1rem = 37.5px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 37.5 = 2rem。 当然,每个布局都要计算非常繁琐,我们可以借助PostCSS的px2rem插件来帮助我们完成这个过程。

但是,现在lib-flexible这个过渡方案已经可以放弃使用,因为当年viewport在低版本安卓设备上还有兼容问题。

而现在viewport单位已经得到众多浏览器的兼容,所以我们可以使用vw,vh 方案

# vw、vh 方案

vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份。
1

vh和vw方案和rem类似也是相当麻烦需要做单位转化,而且px转换成vw不一定能完全整除,因此有一定的像素差。

不过在工程化的今天,webpack解析css 的时候用postcss-loader 有个postcss-px-to-viewport能自动实现px到vw的转化

{
    loader: 'postcss-loader',
    options: {
    	plugins: ()=>[
        	require('autoprefixer')({
        		browsers: ['last 5 versions']
        	}),
        	require('postcss-px-to-viewport')({
        		viewportWidth: 375, //视口宽度(数字)
        		viewportHeight: 1334, //视口高度(数字)
        		unitPrecision: 3, //设置的保留小数位数(数字)
        		viewportUnit: 'vw', //设置要转换的单位(字符串)
        		selectorBlackList: ['.ignore', '.hairlines'], //不需要进行转换的类名(数组)
                minPixelValue: 1, //设置要替换的最小像素值(数字)
                mediaQuery: false //允许在媒体查询中转换px(true/false)
        	})
    	]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# viewport 标签

var $_DESIGN_LAYOUT_WIDTH = 414
<meta name="viewport" content="width=$_DESIGN_LAYOUT_WIDTH ,user-scalable=no,viewport-fit=cover">

// 375 设计稿
<meta name="viewport" content="width=375, user-scalable=no, viewport-fit=cover">

// 414 设计稿
<meta name="viewport" content="width=414, user-scalable=no, viewport-fit=cover">
1
2
3
4
5
6
7
8

固定设备宽度为 UI 稿宽度,开发全部按照UI稿尺寸进行编写,将缩放适配等工作交由浏览器自动完成。

参考:移动端适配 (opens new window)关于移动端适配 (opens new window)一次千万级流量的 618 电商 H5 活动页干货分享 (opens new window)

Last Updated: 4/25/2023, 11:46:07 AM