深圳幻海软件技术有限公司 欢迎您!

移动端常见适配方案

2023-03-01

做移动端页面有一段时间了,总结下工作中常用的几种移动端适配方案。基础网上已经有非常多的基础知识总结,其中容易搞混的概念是视口。meta 标签中的 viewport 属性,就是 视图 的含义视口分为布局视口视觉视口理想视口布局视口也就是 &l

做移动端页面有一段时间了,总结下工作中常用的几种移动端适配方案。

基础

网上已经有非常多的基础知识总结,其中容易搞混的概念是视口。

meta 标签中的 viewport 属性,就是 视图 的含义

视口分为

  • 布局视口
  • 视觉视口
  • 理想视口

布局视口

也就是 <meta name="viewport" content="width=device-width">  width 属性的含义

我们在css中写的所有样式,就是相对于 布局视口 进行布局的

默认情况下,移动端的布局视口并不是屏幕宽度,而是一般在768px ~ 1024px间(大部分情况下980px)

可以通过 document.documentElement.clientWidth 获取 (根据 width  initial-scale 来确定)

视觉视口

视觉视口是指用户通过设备屏幕看到的区域,默认等于当前浏览器的窗口大小(当 initial-scale 为1)

当用户对浏览器进行缩放时,不会改变布局视口的大小,所以页面布局是不变的,但是 缩放会改变觉视口的大小

可以通过 window.innerWidth 获取 (会随着缩放进行改变)

放大页面,此时 window.innerWidth 反而减小 (页面放大,你看到的东西也变少了)

理想视口

理想视口是指网站在移动设备中的理想大小,这个大小就是设备的屏幕大小

也就是 <meta name="viewport" content="width=device-width">  device-width 的含义

可以通过 screen.width 获取 (常量,不会改变)

initial-scale

<meta name="viewport" content="width=device-width, initial-scale=0.5">
  • 1.

根据公式 initial-scale = 理想视口宽度 / 视觉视口宽度

假设理想视口宽度为 414px (device-width),此时设置 initial-scale 为0.5,那么视觉视口宽度就是 414 / 0.5 = 818

如果这时你获取 document.documentElement.clientWidth (布局视口)的值,会发现不是 414px 而是 818px

结论: 布局视口宽度取的是width和视觉视口宽度的最大值

思考题:

<meta name="viewport" content="width=600, initial-scale=2">
  • 1.

假设理想视口宽度为 414px (device-width),此时 document.documentElement.clientWidth (布局视口)的值是多少?

总结

  • document.documentElement.clientWidth : 布局视口,css中一般写成 width=device-width
  • window.innerWidth : 视觉视口,页面缩放都会实时改变该值
  • screen.width : 理想视口,页面屏幕大小(设备独立像素),也就是css中的 device-width

常见适配方案

简单一句话概括:移动端适配就是在进行 屏幕宽度  等比例缩放 

平时我们开发中,拿到的移动端设计稿一般是 750 * 1334 尺寸大小( iPhone6 的设备像素为标准的设计图)。那如果在 750px 设计稿上量出的元素宽度为 100px ,那么在 375px 宽度的屏幕下,这个元素宽度就应该等比例缩放成 50px 

所以适配的难点是:如果实现页面的等比例缩放?

Rem 方案

该方案的核心就是:所有需要动态布局的元素,不再使用 px 固定尺寸,而是采用 rem 相对尺寸

rem 的大小是相对于根元素 html 的字体大小:如果 html  font-size 为100px,那么 1rem 就等于100px

现在我们假定:

750px 屏幕下 html  font-size 为100px,也就是 1rem 为100px,那么 200px 宽度的 .box 元素,就应该写成 2rem

那么现在:

375px 屏幕下,我们需要 .box 元素渲染成 100px

由于 .box 的宽度仍然是 2rem ,因此,这时候我们就需要 1rem 为50px,也就是说,此时 html  font-size 为50px

于是此时,我们可以得出一个公式:

(750) / (100) = (当前屏幕尺寸) / (当前屏幕1rem)

把这个公式进行一次数学转换就能得到:

(当前屏幕1rem) = 100 * (当前屏幕尺寸) / 750

翻译成js语言就是

将代码优化一下

考虑到Andorid端字体渲染的问题以及页面大小变化的监听,最终的代码如下:

注意的是:我们取 100px 作为设计稿的1rem,是因为方便计算,比如设计稿上量出 250px ,我们就可以很容易的计算出为 2.5rem 

我们当然也可以把 50px 作为设计稿的1rem,这时设计稿上的 250px ,就要写成 5rem 

其实我们也可以借助于postcss-pxtorem或者 SCSS 函数来帮我们自动转换单位

通过Rem方案,需要动态缩放的元素,我们使用 rem 相对单位,不需要缩放的元素,我们仍然可以使用 px 固定单位。

不过在大屏设备下(例如ipad或者pc端),由于我们的页面是等比例缩放,这时候页面的元素会被放大很多(屏幕宽度大,导致根元素字体1rem也变大)。但是在大屏下,我们真正希望的是用户看到更多的内容,这时候我们可以使用媒体查询的方式来限制根元素的字体,从而防止在大屏下元素过大的问题。

或者修改js脚本的逻辑

VW 方案

vw 是相对单位,1vw 表示屏幕宽度的 1%

其实我们的 REM方案 就是 VW方案 的模拟,之前我们有一个公式:

(750) / (100) = (当前屏幕尺寸) / (当前屏幕1rem)

换一个转换方式:

(当前屏幕1rem) = (当前屏幕尺寸) / 7.5

而 vw 单位其实就是:

(当前屏幕1vw) = (当前屏幕尺寸) / 100

因此, REM方案 就是用 JS 把屏幕宽度分成了7.5份,而 CSS3 中新增的 vw 单位,原生实现了把屏幕宽度分成了100份

所以,在 VW方案 中,我们不再需要使用JS脚本了!

750px 设计稿中, 1vw 等于 7.5px (750 / 100),因此,在设计稿中,量出 200px 的宽度,就因为写成 26.667vw (200 / 7.5)

不过使用 vw 换算,并不像 rem 那么方便,这时候我们可以借助 postcss-px-to-viewport 或者 SCSS 函数来帮我们自动转换单位

同样,在大屏设备下,由于屏幕宽度大,所以页面的元素同样会放大很多(屏幕宽度大,1vw也很大)。但是由于 vw 是相对屏幕宽度的,所以我们不能像 REM方案 中一样,手动控制 html 的根字体大小,这也是使用 VW方案 的一个缺点。

REM + VW 方案

REM方案 的优势是可以手动控制 rem 的大小,防止屏幕太大时,页面元素也缩放很大,但是缺点就是需要使用 JS  VW方案 刚好相反,无需使用 JS 但是无法手动控制 vw 的大小。

其实我们可以把两者结合:

对于布局元素,我们仍然使用 rem 单位。但是对于根元素的字体大小,我们不需要使用JS来动态计算了

这段js可以直接使用css来实现

对于大屏设备,我们使用媒体查询

更详细的 vw+rem布局方案 可以见 《基于vw等viewport视区单位配合rem响应式排版和布局》

viewport 缩放方案

还有一种更简单粗暴的方法,就是我们设置 initial-scale

我们的布局完全基于设计稿 750px ,布局元素单位也使用 px 固定单位 (布局视口写死750px)

对于 375px 宽度,我们就将整个页面缩放 0.5 

<meta name="viewport" content="width=750, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=0">

此方案的缺点: 整个页面都被缩放了,对于不想缩放的元素无法控制。

市面上一些营销H5页面,由于是通过后台可视化拖拽搭建出来的,为了适配各种尺寸的屏幕,该方案是成本最低的实现(易企秀就是使用这种方案)

实战

我们拿线上B站会员购作为示例

  • rem方案
  • vw方案
  • rem+vw方案
  • viewport方案

请使用chrome开发者工具模拟移动端设备查看

源码直接右键查看即可,代码没有经过压缩,可以很直观的看到各种方案的css适配写法