背景
由于自己太久没开发移动端的页面,个人觉得移动端开发相比较PC端开发最大的不同,在于需要去适配各种尺寸的手机屏幕,尤其还有1px的问题。
因此需要再次收集一下,除了自己认知(rem适配)以外,是否还有移动端适配的方案吗?
问题
移动端存在几类问题,如下所列:
- 1px显示过粗问题
- 手机屏幕出现刘海屏、滴水屏等,如何适配
- 如何在不同屏幕,显示正确高清图片
- meta 的 viewport 值 能否用来适配
- rem,vw,vh计算单位的区别
- …
概念
像素
像素是计算机屏幕上所能显示的最小单位。用来表示图像的单位。
按照我个人理解,把屏幕比做一张白纸,然后像素就是一个点,接着同一水平线上的点形成一条线,水平线和垂直线同时就形成一个画面。
然后对于我们前端开发而言,像素又需要分成几类:
设备独立像素
, 俗称DIP
,你可以理解成我们平时用css像素 又等于 逻辑像素,简单说就是同一个尺寸的屏幕,设备独立像素是一样的,从而减少误解物理像素
,其实就是我们真实肉眼可见的像素,物理像素 = 分辨率设备像素比
,DPR
devicePixelRatio
= 设备像素 / 设备独立像素,当物理像素和设备独立像素不一样的时候,这个时候就需要一个标准来做适配,利用DPR
我们能将同样的画面适应不同的屏幕每英寸像素
ppi
(pixel per inch),表示每英寸所包含的像素点数目,更确切的说法应该是像素密度。数值越高,说明屏幕能以更高密度显示图像
分辨率
分辨率指屏幕上像素的数目,一般用水平垂直,比如:屏幕分辨率为 800 600, 水平有800个像素点,垂直有600个像素
所以平时我们将2k、4k屏幕,通常指的是水平方向的存放像素超过2000或4000个。
视口(viewport)
视口代表当前可见的计算机图形区域。在 Web 浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的 UI,菜单栏等——即指你正在浏览的文档的那一部分。
视口一般是指用户访问页面时,当前的可视区域范围。通过滚动条滑动,视口可以显示页面的其他部分。
通过 document.documentElement.clientWidth 或 window.innerWidth 可以获取视口宽度。
简单的说,视口就是浏览器肉眼可见的区域,是随时可变化,视口是一个概念,它又可以根据不同情况分为以下几种:
- 布局视口,对于开发来说的一种视口概念,在移动端可以通过
<meta name="viewport" content="width=980, initial-scale=1.0"></meta>
调整从而将打屏显示的内容完整缩小适配到移动端小屏 - 视觉视口,是一种针对移动端屏幕提出来的概念,具体是指的屏幕的可见区域,当键盘弹起、浏览器工具栏隐藏等,视觉视口都会随之变化,而布局视口不会
布局视口(layout viewport)
innerHeight 和 innerWidth 所组成的区域通常被认为是布局视口(layout viewport)。浏览器的框架不被认为是视口的一部分。
在PC端的时候, 视口=布局视口=视觉视口。
在移动端的时候,布局视口 = 内容宽度,可以通过<meta name="viewport" content="width=980, initial-scale=1.0"></meta>
调整,下面举几个例子(移动端为375*667):
<meta name="viewport" content="width=980, initial-scale=1.0"></meta>
, 布局视口=window.innerWidth=980<meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
, 布局视口=window.innerWidth=375
视觉视口(visual viewport)
视觉视口指当前浏览器中可见的部分,并且可以变化。当使用双指缩放,或键盘在手机上弹出的时候,或者之前隐藏的地址栏变得可见的时候,视觉视口缩小了,但是布局视口却保持不变。
相比较布局视口
概念,视觉视口是由苹果 乔布斯提出,为了更好的在移动端展示web网页,视觉视口=屏幕的可见区域,下面通过几个例子去认知(移动端为375*667):
<meta name="viewport" content="width=980, initial-scale=1.0"></meta>
,视觉视口=window.screen.width=375<meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
,视觉视口=window.screen.width=375
viewport设置项
viewport
的设置主要是在移动端配置视口大小,从width宽度,initial-scale缩放等设置属性,具体如下:
- width:控制 viewport 的大小,可以给它指定一个值(正整数),或者是一个特殊的值(如:device-width 设备独立像素宽度,单位缩放为 1 时);
- initial-scale:初始缩放比例,即当页面第一次加载时的缩放比例,为一个数字(可以带小数);
- maximum-scale:允许用户缩放到的最大比例,为一个数字(可以带小数);
- minimum-scale:允许用户缩放到的最小比例,为一个数字(可以带小数);
- user-scalable:是否允许用户手动缩放,值为 “no”(不允许) 或 “yes”(允许);
- height:与 width 相对应(很少使用)。
注意项
- iframe的视口等于是其内部高度和宽度的大小。
- SVG的视口即 SVG 图片的可视区域。
方案
这些兼容方案都是基于视口不缩放配置才能生效:<meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
目前市面主流的几种适配方案如下:
rem
,通过一个宽度尺寸作为统一的单位值,然后通过js计算出不同尺寸对比值,得到适配效果vw
,一个浏览器支持的单位,利用 CSS 视窗的特性,总宽度为 100vw,每一份为一个单位 1vw,设置 1rem 单位为 10vwpx + calc + clamp
,大漠在2021年提出,根据 CSS 的新特性:css变量、calc()函数、clamp()、@container函数实现
rem方案
rem
是指的html元素的font-size
的大小,如:html{font-size:50px}; 1rem=50px
。
实现原理
通过一个具体的例子,更好理解它的原理。比如你拿到一张设计稿为750px宽度的,里面有个长方形为100*200,这个时候需要在不同屏幕去做适配。
rem的解决方案思路为:
- 将标准尺寸宽度 750/10= 75px,设置:
html{font-size:75px} 1rem=75px
- 将长方形的 100*200,100/75 * 200/75,设置为:
.rectangle{width: 1.33rem;height:2.66rem}
- 那么当屏幕的尺寸发生变话的时候, 变成从750减少为375,那么这个时候,设置:
html{font-size:37.5px} 1rem=37.5px
- 长方形的css设置无需变化,从而达到适配的效果
所以rem的解决方案就是在web应用在加载的时候,提前计算好rem单位,所以就可以完成适配。
目前主流的方案有:
源码实现:
PS: 里面涉及到pageshow
事件,基本上是因为移动端缓存了web页面,当浏览器历史记录前进或后退的是会触发,可以通过e.persisted
判断是否从缓存获取
缺点:
- 需要前置js才能实现,根据设备的视窗宽度进行计算,影响性能
- 在 PC 端浏览破相,一般设置一个最大宽度
vw方案
是什么
vw是css的一种计算单位,定义:
1vw 等于1/100的视口宽度 (Viewport Width)
同理vh也是:
1vh 等于1/100的视口高度 (Viewport Height)
那么vmax,vmin,我在网上找到比较好解释如下:
vmin — vmin的值是当前vw和vh中较小的值。
vmax — vw和vh中较大的值。
在横竖屏的切换中,十分有用。
原理
了解到vw的概念,那么如何利用vw去解决移动端的适配呢?其实和rem方案是一样,具体代码可以如下:
1 | /* rem 方案 */ |
已实现的框架方案如下:
利用打包编译过程,将设置好的px单位转换为vw或vh,具体使用可以看使用文档。
缺点:
- 和rem一样,容易在pc端适配错误,可以用@media媒体查询去做样式兼容
后续添加
如果利用flex/grid布局,加上vw、vh单位,是否可以做到自适应布局呢?
答案是肯定,而且相对而言会比其他方案,会更加容易开发些,实现步骤如下:
- 利用flex弹性布局,加上vw设置flex弹性盒子的宽度,从而做到不同宽度屏幕,是否换行或者垂直布局
后续可以专门写个文章用来描述flex布局的原理。
px + calc + clamp
是什么
calc()
此 CSS 函数允许在声明 CSS 属性值时执行一些计算。 支持 + , - , / ,* 等运算。
1 | /* property: calc(expression) */ |
clamp()
函数的作用是把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用。它接收三个参数:最小值、首选值、最大值。
1 | font-size: clamp(1rem, 2.5vw, 2rem); |
- 当
2.5vw
大于2rem
,使用2rem - 当
2.5vw
小于1rem
,使用1rem - 其他使用
2.5vw
单位
原理
了解到上面css两个函数,如果通过只用px单位去做适配呢?原理步骤如下:
- 假设我们拿到的设计稿750px宽度,那么这个时候有个长方体是200*100
- 利用css变量,设置一个首先值,然后计算出去其他尺寸所需的最大值、最小值,设置clamp()
- 同时利用calc()去计算偏差值
缺点:
- calc 和clamp 函数在浏览器支持度还不够
- 需要了解这套方案还需要较深的技术方案
1px高清显示问题
1像素问题: 1像素指在 Retina 屏显示 1单位物理像素
- 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
解决方案:
- 渐变实现 : background-image: linear-gradient(to top, ,,,)
- 使用缩放实现:transform: scaleY(0.333)
- 使用图片实现:base64
- 使用 SVG 实现:嵌入 background url
- border-image,低端机下支持度不好
以上方案都是基于媒体查询解决的
1 | @media only screen and (-webkit-min-device-pixel-ratio: 2), |
媒体查询
媒体查询(Media queries)非常实用,尤其是当你想要根据设备的大致类型(如打印设备与带屏幕的设备)或者特定的特征和设备参数(例如屏幕分辨率和浏览器视窗宽度)来修改网站或应用程序时。
使用
一般有几种用法,如下所示:
- 通过
@media
和@import at-rules
用CSS 装饰样式 - 用
media=
属性为<style>, <link>, <source>
和其他HTML元素指定特定的媒体类型 - 使用
Window.matchMedia()
和MediaQueryList.addListener()
方法来测试和监控媒体状态
CSS装饰样式用法
1 | @media screen, print { ... } |
HTML元素引入
1 | <link rel="stylesheet" src="styles.css" media="screen" /> |
js用法
1 | let mql = window.matchMedia('(max-width: 600px)'); |
图片高清问题
图片高清问题,一般是指的:不同 DPR 下图片的高清解决方案。
这种问题解决方案,通常是利用媒体查询+提供不同尺寸的图片去显示。
总结
移动端适配方案,结合开发中,大家都是直接写px,然后利用编译过程的进行转换,比如: px2rem
,px2vw
。
再就是排版问题,不同屏幕问题需要做自动排版优化方案,这个需要后面去研究一下《如何正确的使用 CSS Clamp 进行响应式排版》。
- 本文作者: qborfy
- 本文链接: https://www.qborfy.com/today/20220111.html
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!