熟悉又陌生的移动端适配

学前端

共 3427字,需浏览 7分钟

 ·

2020-12-05 07:32

什么是移动端适配

在不同尺寸的移动设备上,让页面达到合理的展示或者说等比缩放展示

分辨率

  • 逻辑分辨率:它是软件和硬件(物理分辨率)之间的一个转换层,可通过 window.screen.width 获取宽度,视口大小就是参照该值进行缩放。
  • 物理分辨率:它是设备硬件固有的分辨率,出厂后就固定,可通过查看设备屏幕参数获取,也可通过 window.screen.width * window.devicePixelRatio 获取。

历代 iphone 分辨率:

设备逻辑分辨率物理分辨率dpr = 物理分辨率 / 逻辑分辨率PPI
iphone 3G320 x 480320 x 480@1x163
iphone 4/4s320 x 480640 x 960@2x163
iphone 5/5s320 x 568640 x 1136@2x326
iphone 6/6s375 × 667750 × 1334@2x326
iphone X/Xs375 × 8121125 × 2436@3x458

像素密度 PPI

像素密度 PPI (Pixel Per Inch) 是指每英寸的长度(2.54 cm)中容纳的像素个数。

58651ea237385766973c7906f17c2288.webp

PPI

问:一像素到底有多大?

答:1 像素长度 = 2.54 / PPI

例:1 像素长度(iphone 6) = 2.54 / 326 = 0.0779 mm = 头发直径(0.06 ~ 0.09 mm)

viewport 相关

概念

移动设备上的 viewport 就是设备屏幕上能用来显示网页的那一块区域,又叫「视口」,代码就是根据视口宽度进行排列布局的。但 viewport 又不仅仅是浏览器可视区域的大小,它可能比浏览器可视区域大,也可能比它小。默认情况下,移动设备的 viewport 要大于浏览器可视区域,这主要是用来兼容显示 PC 端的网站(iPhone 默认宽度 980px)。

控制 viewport

通过 meta 标签控制 viewport 大小,下面代码是将 viewport 的宽度等于逻辑分辨率

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

width 和 initial-scale 的取值有冲突,width=device-widthinitial-scale=1.0 是等效的,这两个值都可以设置初始视口大小,如果同时设置时在 Safari 和部分 Android 浏览器上会选择使用较大值。各个浏览器表现可能不一致,为了统一应该只使用其中一个值,使用 initial-scale=1.0 更方便计算。

视口宽度 = 逻辑分辨率 / initial-scale

可以通过 document.documentElement.clientWidth 来获取 viewport 的宽度(不包括滚动条)。

移动端适配的方式

所谓的移动端适配,就是说页面内的元素宽高,是根据不同逻辑分辨率自动改变的。那什么样的长度单位能够满足呢?答案是通过 vw 或 rem(需要 js 根据设备宽度计算得出值) 单位来达到适配的目的。

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

rem

兼容 IOS 4.1+, Android 2.1+ 可看这里[1]

通过 meta 标签设置视口的宽度等于设备宽度,如下:

<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

rem 这个单位代表根元素(通常为 元素)的 font-size 大小,通过当前设备宽度来设置跟元素的字体大小,来达到移动端适配的目的。

一般是参照设计稿来进行开发,假如设计稿的宽度为 375px,那怎么通过 rem 来进行适配呢?

在不同尺寸的设备上,通过 js 按照设计稿的宽度等比例计算根元素的字体大小,这样才不会失真。

比如,设计稿的宽度为 375px 时的根字体大小为 100px 也就是 1rem,那当前设备下的根字体为多少?因为是等比缩放,所以通过如下等式可计算得出当前根字体(currentRootFontSize)值。

设计稿根字体大小(随意设定) / 设计稿宽度 = 当前根字体大小 / 视口宽度

因为:100px / designWidth = currentRootFontSize / viewportWidth

所以:currentRootFontSize = viewportWidth * 100px / designWidth

用代码可表示为:

const designWidth = 375 // 设计稿宽度
const viewportWidth = document.documentElement.clientWidth // 当前视口宽度
document.documentElement.style.fontSize = (viewportWidth / designWidth) * 100 + 'px' // 根字体大小

上面是设备像素比(dpr)为 1 的计算方式。但是移动适配往往存在 1 像素问题,因为 px 是逻辑像素,跟屏幕上的物理像素有可能不是 1:1 的关系,所以就有可能出现,1px 对应 2 个或多个物理像素的情况。

当 dpr > 1 时,同时想保证 1px 始终对应 1 个物理像素,那就需要让根字体扩大 dpr 的倍数,同时通过 meta 标签让视口缩小 1/dpr 倍即可。

例如:当 dpr = 2 时


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

优点:

  • 使用 meta initial-scale 来缩放,解决了 1px 问题

缺点:

  • 需要额外的 js 逻辑来控制根字体大小
  • 逻辑不直观,需要根字体大小进行转换
  • initial-scale 进行视口缩放后,第三方 UI 库组件显示有影响,需要额外处理

采用 rem 进行移动端适配,是个历史过程,因为早期 rem 兼容性比 vw 好,但现在而言,项目没有要求太高兼容性的情况下,完全可以使用 vw 进行移动端适配。

vw

1vw 等于视口宽度的 1%,它是天生的移动端适配单位,无需多余转换。

兼容 IOS 8+, Android 4.4+ 可看这里[2]

优点:

  • 无需引入多余 js 逻辑
  • 语义化,vw 逻辑清晰,不需要像 rem 那样需要换算一下

缺点:

  • 1px 问题需要额外处理

react 项目应用

postcss-px-to-viewport[3] 是将 px 转换成视口单位(vw、vh)的 PostCss[4] 插件

// 项目中配置

addPostcssPlugins([
  require('postcss-px-to-viewport')({
    viewportWidth375// 视窗的宽度,对应的是我们设计稿的宽度
  }),
]),

参考

  • Window.devicePixelRatio[5]
  • 移动前端开发之 viewport 的深入理解[6]
  • vw 相比 rem,在实际开发中究竟有多大区别?[7]
  • iPhone 屏幕分辨率和适配规则(基础篇)[8]
  • 逻辑分辨率和物理分辨率到底是什么呀?[9]

参考资料

[1]

可看这里: https://caniuse.com/#feat=rem

[2]

可看这里: https://caniuse.com/#feat=viewport-units

[3]

postcss-px-to-viewport: https://github.com/evrone/postcss-px-to-viewport/blob/master/README_CN.md

[4]

PostCss: https://github.com/postcss/postcss

[5]

Window.devicePixelRatio: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/devicePixelRatio

[6]

移动前端开发之 viewport 的深入理解: https://www.cnblogs.com/2050/p/3877280.html

[7]

vw 相比 rem,在实际开发中究竟有多大区别?: https://www.zhihu.com/question/37179916/answer/101810379

[8]

iPhone 屏幕分辨率和适配规则(基础篇): https://www.jianshu.com/p/41a8ccdf91ed

[9]

逻辑分辨率和物理分辨率到底是什么呀?: https://www.zhihu.com/question/40506180


浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报