乐趣区

关于javascript:移动端法门自适应方案和高清方案

笔者从毕业开始做前端到当初,90% 的我的项目是挪动端打交道,所以当简历上写了“挪动 H5”几个字时,必会被问到自适应计划与高清计划

”自适应“讲的是一套 UI(例如 750*1334),在多端下展现近乎一样的成果;而”高清“是因为 DPR 晋升而所做的各种精度适配

这篇文章讲讲笔者了解的自适应计划和高清计划

先说论断

自适应计划

  • rem

    • 适配思路

      • 抉择一个尺寸作为设计和开发基准
      • 定义一套适配规定,主动适配残余的尺寸
      • 非凡适配成果给出设计成果
    • 属于 历史产物,CSS 视窗单位未失去支流浏览器的反对
    • 原理

      • 依据视窗宽度动静调整根元素 html 的 font-size 的值
      • 把总宽度设置为 100 份,每一份被称为一个单位 x,同时设置 1rem 单位为 10x
    • 毛病

      • 须要加载 js 脚本,而且依据设施的视窗宽度进行计算,影响性能
    • 影响力:从 2015 年入世至今,在 H5 适配畛域占据肯定比例
    • 相干技术库:flexible、px2rem
  • vw

    • 适配思路(如上)
    • 原理

      • 利用 CSS 视窗的个性,总宽度为 100vw,每一份为一个单位 1vw,设置 1rem 单位为 10vw
    • 毛病

      • 因为是依据视图的宽度计算,所以不实用平板和 PC
    • 影响力:2018 年出的计划,目前 H5 适配支流
    • 相干技术库:postcss-px-to-viewport
  • px + calc + clamp

    • 适配思路

      • 依据 CSS 的新个性:css 变量、calc()函数、clamp()、@container 函数实现
    • 特点

      • 解决了 rem、vw 布局的致命毛病:失去像素的完美性,而且一旦屏幕低于或高于某个阈值,通常就会呈现布局的挪动或文字内容的溢出
      • 大漠在 2021 年提出,最先进,但没看到大厂应用(clamp 函数浏览器支持率暂且不高),具体能够看看大漠的这篇:如何构建一个完满缩放的 UI 界面
    • 毛病

      • 因为计划先进,暂没看到大厂应用

高清计划

  • 1 像素问题的解决方案
  • 不同 DPR 下图片的高清解决方案

综上,自适应计划是解决 各终端的适配问题,高清计划是解决Retina 屏的细节解决

写在后面

在说挪动端适配计划之前先整明确一些技术概念

设施独立像素

设施独立像素(DIP)=== CSS 像素 === 逻辑像素,在 Chrome 中能间接看到 375* 667

当你看到设施独立像素时,不要慌,它示意 CSS 像素,而它的长宽就是在 Chrome 中所查到的。可这样记忆,“设施独立像素”,字数长,文绉绉就是 CSS 像素,也是实践上人为给定的指标,也叫逻辑像素

物理像素

物理像素能够了解为手机厂商在卖手机时宣传的分辨率,即物理像素 = 分辨率,它示意垂直和程度上所具备的像素点数

也就是说设施屏幕的程度方向上有 1920 像素点,垂直方向有 1080 像素点(假如屏幕分辨率为 1920*1080),即屏幕分辨率示意物理像素,它在出厂时就定下来,单位为 pt,1pt=0.376mm

物理像素,又被称为设施像素,即示意 设施像素 === 物理像素。可这样记忆,设施在物理世界能测量的长度

DPR(Device Pixel Ratio)

而设施像素比(DPR)是什么?

DPR = 设施像素 / 设施独立像素,它通常与视网膜屏(Retina 屏)无关

以 iPhone7 为例子,iPhone7 的 DPR = iPhone7 物理像素 / iPhone7 设施独立像素 = 2

宽 1334 / 667 = 2

高 750 / 375 = 2

失去 iPhone7 的 DPR 为 2,也就是咱们常说的视网膜屏幕,而这就是营销术语,它就是因为技术的提高,使得一个 CSS 像素塞入更多的物理像素

营销术语还有哪些:农夫山泉的大自然的搬运工、元气森林的“気”

笔者是这么记忆的:

  • CSS 像素(设施独立像素)就像一个容器,以前是一比一塞入,所以 DPR 为 1,起初技术倒退提高了,一个容器中能塞入更多的实在像素(物理像素)
  • DPR = 设施像素 / 设施独立像素
  • DPR = 物理像素(实在)/ CSS 像素(虚的)

在视网膜屏幕中,以 DPR = 2 为例,把 4(2×2)个物理像素当一个 CSS 像素应用,这样让屏幕看起来更加清晰(粗劣),然而元素的大小(CSS 像素)自身不会扭转

随着硬件的倒退,像 iPhone13 Pro 等手机的 DPR 曾经为 3,将来 DPR 冲破 4 不是问题

说回来,DPR 为 2 或 3 会有什么问题?咱们以 CSS 为最小单位来写代码的,展现在屏幕上也是以 CSS 为最小单位来展现,也就是说在 DPR 为 2 时,咱们想要模仿 1 单位物理像素 是做不到的(如果浏览器反对用 0.5px CSS 的话,能够模仿,然而 DPR 为 3 呢,用 0.333px?);又因为手机的设施独立像素(CSS 像素)固定,应用传统动态布局(固定 px)时,会呈现款式的错位

iPhone 5/SE: 320 * 568 DPR: 2

iPhone 6/7/8: 375 * 667 DPR: 2

iPhone 6/7/8 Plus: 414* 736 DPR: 3

iPhone X: 375 * 812 DPR: 3

所以咱们要适配各终端的 CSS 像素以及不同 DPR 下,呈现的 1 像素问题、图片高清问题等。随着技术的倒退,前端们解脱了 IE 的兼容,同时陷入了各大手机品牌的兼容沼泽

自适应计划

Rem 布局——天下第二

简介:rem 就是绝对于根元素 html 的 font-size 来做计算

与 rem 相关联的是 em:

em 作为 font-size 单位时,其代表父元素的字体大小,em 作为其它属性单位时,代表本身字体大小

rem 作用于非根元素时,绝对于根元素字体大小,rem 作用于根元素字体时,绝对于其初始字体大小

实质:等比缩放,是通过 JavaScript 来模仿 vw 的个性

假如将屏幕宽度均匀分为 100 份,每一份的宽度用 x 示意,x = 屏幕宽度 / 100,如果将 x 作为单位,x 后面的数值就代表屏幕宽度的百分比

p {width: 50x} /* 屏幕宽度的 50% */ 

如果想要页面元素随着屏幕宽度等比变动,咱们就须要下面的 x,这个 x 就是 vw,然而 vw 是在浏览器反对后才大规模应用,在此之前,js + rem 可模仿这种成果

之前说了,rem 作用于非根元素时,绝对于根元素字体大小,所以咱们设置根元素单位后,非根元素应用 rem 做绝对单位

html {font-size: 16px}
p {width: 2rem} /* 32px */

html {font-size: 32px}
p {width: 2rem} /* 64px */

问题来了,咱们要获取到一个动静的根元素 font-size,并以此变动各个元素大小

乏味的是,我司两个我的项目目前的做法是通过媒体查问设置根元素,分为四档,默认 16px

笔者对这种做法示意不了解,原开发人员说咱们这套运行了 6 年,UI 适配也没人说什么问题。这里就有个疑难了,真的如他所说 UI 适配的很好吗,”媒体查问根元素 +rem“也能适配好吗?是否完满呢?

后续笔者也会在 demo 中展现这种做法

然而根元素的 font-size 怎么变动,它不可能始终是 16px,在中大屏下还能够,然而在小屏下字体就太大了,所以它的大小也应该是动静获取的。如何让其动态化,就是上文所说,让根元素的 font-size 大小恒等于屏幕宽度的 1/100

html {font-size: width / 100};

如何设置 html 的字体大小恒等于屏幕宽度的百分之一呢?能够通过 js 来设置,个别需在页面 dom ready、resize 和屏幕旋转中设置

document.documentElement.style.fontSize = document.documentElement.clientWidth / 100 + 'px';

flexible 源码就如以上思路写的

咱们设置了百分之一的宽度后,在写 css 时,就须要利用 scss/less 等 css 处理器来对 css 编译解决。假如给出的设计图为 750 * 1334,其中一个元素宽度为 200 px,依据公式:

width: 200 / 750 * 100 = 26.67 rem

在 sass 中,须要设置设计图宽度来做换算:

@use 'sass:math';

$width: 750px;

@function px2rem($px) {@return #{math.div($px, $width) * 100}rem;
}

下面编译完后

div {width: 26.667rem}

在不同尺寸下,它的宽度不同

机型 尺寸 width
iPhone 5/SE 320 * 568 170 * 170
iPhone 6/7/8 375 * 667 200 * 200
iPhone 6/7/8 Plus 414 * 736 220.797 * 220.797
iPhone X 375 * 812 200 * 200

成果如下(特意阐明:图中演示的是引入 flexible 库,它的根元素的 font-size 为屏幕的 1/10)

REM 布局(flexible)demo

长处:rem 的兼容性能低到 ios 4.1,android 2.1

毛病:

  • 等比放大(能够说长处也能够了解为毛病,不同场景下应用)

    • 用户抉择大屏幕有几个出发点,有些人想要更大的字体,更大的图片,有些人想要更多的内容,并不想要更大的图标
  • 字体大小不能应用 rem(个别应用媒体查问管制 font-size 大小)
  • 在 PC 端浏览破相,个别设置一个最大宽度
var clientWidth = document.documentElement.clientWidth;
clientWidth = clientWidth < 780 ? clientWidth : 780;
document.documentElement.style.fontSize = clientWidth / 100 + 'px';
body {
    margin: auto;
    width: 100rem;
}
  • 如果用户禁止 js 怎么办?

    • 增加 noscripe 标签提醒用户
    • <noscript> 开启 JavaScript,取得更好的体验 </noscript>
    • 给 HTML 增加一个 默认字体大小

相干技术计划:flexible(amfe-flexible 或者 lib-flexible)+ postcss-pxtorem

Viewport 布局——天不生我 VW,适配万古如长夜

vw 是基于 Viewport 视窗的长度单位,这里的视窗(Viewport)指的是浏览器可视化的区域,而这个可视区域是 window.innerWidth/window.innerHeight 的大小

依据 CSS Values and Units Module Level 4:vw 等于初始蕴含块(html 元素)宽度的 1%,也就是

  • 1vw 等于 window.innerWidth 的数值的 1%
  • 1vh 等于 window.innerHeight 的数值的 1%

看图了解

在说 rem 布局时,已经举过 x 的例子,x 就是 vw

/* rem 计划 */
html {font-size: width / 100}
div {width: 26.67rem}

/* vw 计划 */
div {width: 26.67vw}

vw 还能够和 rem 计划联合,这样计算 html 字体大小就不须要 js 了

html {font-size: 1vw}
div {width: 26.67rem}

成果如下:

vw 适配是 CSS 原生反对,而且目前兼容性大多数手机是反对的,也不须要加载 js,也不会因为 js 引发性能问题

vw 的确看上去很不错,然而也存在一些问题

  • 也没能很好的解决 1px 边框在高清屏下的显示问题,须要自行处理
  • 因为 vw 计划是齐全的等比缩放,在 PC 端上会破相(和 rem 一样)

相干技术计划:postcss-px-to-viewport

VW 布局 demo

px 适配——一力降十会

不必 rem/vw,用传统的响应式布局也能在挪动端布局中应用,须要设计规范

应用 css 变量 适配(篇幅起因暂不具体介绍,可间接看代码)

应用场景:新闻、内容型的网站,不太实用 rem,因为大屏用户想要看到更多的内容,如网易新闻、知乎、taptap

PX + CSS 变量 demo

媒体查问——可有我一席?

上文讲到我司原先 H5 端采纳媒体查问的形式来做适配,笔者尝试复刻了下,只能说大差不差,能看出媒体查问想做成这件事,但还是爱莫能助

采纳 rem、vw、px 等办法能实现非标准尺寸(375 667 设计稿)下 header 的高度为 165.59px,而 media 因为大屏,将根 font-size 设置为 17px,后果 header 的高度成为 159.38px(17 9.375rem)

如下 GIF 所示:

所以说仅用媒体查问还是差强人意

媒体查问布局 demo

各种适配的比照

vw、rem 适配的实质都是等比例缩放,px 间接写,孰优孰劣看本人

REM 布局 VW 布局 PX + css 变量布局
容器最小宽度 反对 不反对 反对
容器最大宽度 反对 不反对 反对
高清设施 1px 边框 反对 反对 反对
容器固定纵横比 反对 反对 反对
长处 1. 老牌计划
2. 反对高清设施 1px 边框时,可按以往形式间接写
1. 无需引入 js
2. 人造反对,写法标准
同 VW
毛病 1. 须要引入 js 设置 html 的 font-size
2. 字体大小不能应用 rem
3. 在 PC 端浏览会破相,个别需设置最大宽度
1. 在 PC 端会破相
2. 不反对老旧手机
同 VW

除此之外,还有搭配 vw 和 rem 的计划

  • 给根元素大小设置随着视窗变动而变动的 vw 单位,动态变化各元素大小
  • 限度根元素字体大小的最大最小值,配合 body 加上最大宽度和最小宽度
// rem 单位换算:定为 75px 只是不便运算,750px-75px、640-64px、1080px-108px,如此类推
$vm_fontsize: 75; // iPhone 6 尺寸的根元素大小基准值
@function rem($px) {@return ($px / $vm_fontsize) * 1rem;
}
// 根元素大小应用 vw 单位
$vm_design: 750;
html {font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw; 
    // 同时,通过 Media Queries 限度根元素最大最小值
    @media screen and (max-width: 320px) {font-size: 64px;}
    @media screen and (min-width: 540px) {font-size: 108px;}
}
// body 也减少最大最小宽度限度,防止默认 100% 宽度的 block 元素追随 body 而过大过小
body {
    max-width: 540px;
    min-width: 320px;
}

高清计划

1 像素问题

1 像素指在 Retina 屏显示 1 单位物理像素

很好了解,CSS 像素(设施独立像素)是咱们人为规定的,当 DPR 为 1 时,1 像素(指咱们写的 CSS 像素)等于 1 物理像素;但当 DPR 为 3 时,1 像素就为 3 物理像素

  • DPR = 1,此时 1 物理像素 等于 1 CSS 像素
  • DPR = 2,此时 1 物理像素等于 0.5 CSS 像素

    • border-width: 1px,这里的 1px 其实是 1 CSS 像素宽度,等于 2 物理像素,设计师其实想要的是 border-width: 0.5px
  • DPR = 3,此时 1 物理像素等于 0.33 CSS 像素

    • 设计师想要的是 border-width: 0.33px

解决思路

应用 0.5px。有局限性,iOS 8 及以上,苹果零碎反对,然而 iOS 8 以下和 Android(局部低端机),会将0.5px 显示为 0px

既然 1 个 CSS 像素代表 2(DPR 为 2)、3(DPR 为 3)物理像素,设施又不意识 0.5px 的写法,那就画 1px,而后想方法将宽度缩小一半

计划

  • 突变实现

    • background-image: linear-gradient(to top, ,,,)
  • 应用缩放实现

    • transform: scaleY(0.333)
  • 应用图片实现

    • base64
  • 应用 SVG 实现

    • 嵌入 background url
  • border-image

    • 低端机下反对度不好

以上都是通过 CSS 的媒体查问来实现的

@media only screen and (-webkit-min-device-pixel-ratio: 2),
    only screen and (min-device-pixel-ratio: 2) {}
@media only screen and (-webkit-min-device-pixel-ratio: 3),
    only screen and (min-device-pixel-ratio: 3) {}

图片适配和优化

图像通常占据了网页上下载资源绝大部分,优化图像通常能够最大限度地缩小从网站下载的字节数以及进步网站性能

通常能够,有一些通用的优化伎俩:为不同 DPR 屏幕提供最适宜的图片尺寸

各大厂商的适配剖析

看了不少文章,相似如:大厂是怎么做挪动端适配的

各大厂,有用 rem 适配的、也有用 vm 适配的、也有 vm+rem 联合适配的,纯用 px 计划的也有

  • 新闻、社区等可浏览内容较多的场景:px+flex+ 百分比

    • 如携程、知乎、TapTap
  • 对视觉组件品种较多,依赖性较强的挪动端页面:vw+rem

    • 如电商、论坛

总结

rem 计划,引入 amfe-flexible

设计:设计出图是 750 * 1334,设计切好图后,上传蓝湖,依照尺寸写 px。

开发:

  • 应用 rem 计划

    • 引入 amfe-flexible
    • 装置 px2rem 之类的 px 转 rem 工具
    • 配置 px2rem
    • 在我的项目中写 px,输入时是 rem
    • 实用任何场景
  • 应用 vw 计划

    • 装置 px2vw 之类的 px 转 vw 工具
    • 配置 px2vw
    • 在我的项目中写 px,输入时是 vw
    • 实用任何场景
  • 应用 px 计划

    • 该怎么样就怎么写,不过因为有设计规划,按钮的大中小尺寸固定、icon 的尺寸有规范、TabBar 的高度也是写死的,当所有都有规范后,写页面就不便了
    • 例如

      • 右边固定 100 * 50,左边 flex 布局
      • 右边固定 100 * 50,左边 calc(100% – 100px)(应用 CSS3 中的 calc 计算)

其余

caniuse 网站测试 CSS 属性与浏览器的兼容性问题

疑难

Q:为什么 H5 挪动端 UI 库单位大都是用 px?这样不会有适配问题吗?

其实咱们写好 px 后,如果我的项目采纳 rem 写业务,引入 px2rem(曾经六年没有保护了)即可转换。

在有赞 vant 库中,它对浏览器适配的介绍是:

Viewport 布局

Vant 默认应用 px 作为款式单位,如果须要应用 viewport 单位(vw、vh、vmin、vmax),举荐应用 postcss-px-to-viewport 进行转换

postcss-px-to-viewport 是一款 PostCSS 插件,用于将 px 单位转化为 vw/vh 单位

Rem 布局

如果须要应用 rem 单位进行适配,举荐应用以下两个工具:

  • postcss-pxtorem 是一款 PostCSS 插件,用于将 px 单位转化为 rem 单位
  • lib-flexible 用于设置 rem 基准值

demo 合集:线上 demo

参考资料

  • 前端基础知识概述 — 挪动端开发的屏幕、图像、字体与布局的兼容适配
  • Rem 布局的原理解析
  • 再谈 Retina 下 1px 的解决方案
  • 再聊挪动端页面的适配
  • 如何在 Vue 我的项目中应用 vw 实现挪动端适配
  • 细说挪动端 经典的 REM 布局 与 新秀 VW 布局
退出移动版