前端兼容性问题 - 屏幕尺寸兼容

写在前面

前端开发最让人头疼的莫过于兼容性问题,继上一篇 前端兼容性问题 - CSS、JS 兼容 之后,这一篇主要研究并解决屏幕尺寸的兼容性问题

目录:

  • 当前现状
  • 解决方案
  • 模拟设备测试方案

当前现状

Android 设备情况

根据OpenSignal 在 2015 年 8 月发布的基础统计数据可以知道Andoroid的设备复杂度:ANDROID FRAGMENTATION VISUALIZED

iOS 设备情况

苹果公司目前已推出42款iPhone型号:维基百科

常见屏幕分辨率

下面列出桌面端、移动端、平板电脑端的一些常见的屏幕分辨率,更多屏幕分辨率查阅:屏幕尺寸大全

桌面端常见屏幕分辨率(显示器)

  1. 1280x720:720p,高清分辨率
  2. 1280x1024:常见于 4:3 屏幕比例的显示器
  3. 1366x768:现在非常常见的低分辨率显示器
  4. 1600x900:较高的分辨率,常见于中等尺寸显示器
  5. 1920x1080:1080p,全高清分辨率,现在非常常见,适用于大多数显示器
  6. 2560x1440:2K 分辨率,适用于较大尺寸或高质量显示器
  7. 3840x2160:4K 分辨率,适用于高端大尺寸显示器

移动端常见屏幕分辨率(智能手机)

  1. iPhone 6、iPhone 6s、iPhone 7、iPhone 8 和 iPhone SE(第二代)的分辨率
  2. 828x1792:iPhone XR 和 iPhone 11 的分辨率
  3. 1080x1920:许多 Android 设备的分辨率
  4. 1125x2436:iPhone X、iPhone XS 和 iPhone 11 Pro 的分辨率
  5. 1170x2532:iPhone 12 和 iPhone 12 Pro 的分辨率
  6. 1440x2560:许多高端 Android 设备的分辨率

平板电脑端常见屏幕分辨率

  1. 1536x2048:iPad 的 Retina 分辨率,如 iPad 3、iPad 4、iPad Air 和 iPad mini(2 代及以后)
  2. 1668x2224:iPad Air(第三代)和 iPad Pro 10.5 英寸
  3. 2048x2732:iPad Pro 12.9 英寸
  4. 800x1280:许多 Android 平板电脑的分辨率
  5. 1200x1920:许多高端 Android 平板电脑的分辨率

屏幕纵横比

统计以上的屏幕分辨率得出多端各自的主流纵横比

桌面端 移动端 平板电脑端
主流纵横比 * 16 : 9 * 16 : 10 * 21 : 9 * 19 : 9 * 19.5 : 9 * 16 : 9 * 4 : 3 * 16 : 9

解决方案

设置 meta 标签

先了解:viewport

viewport 表示浏览器中用来显示网页的可视区域。viewport 包括以下三种:

  1. layout viewport

layout viewport 为网页布局的区域,它是 html 元素的父容器 ,只要不在 css 中修改 元素的宽度, 元素的宽度就会撑满 layout viewport 的宽度。

很多时候浏览器窗口没有办法显示出 layout viewport 的全貌 ,但是它确实是已经被加载出来了,这个时候滚动条就出现了,你需要通过滚动条来浏览 layout viewport 其他的部分

layout viewport 用 css 像素来衡量尺寸,在缩放、调整浏览器窗口的时候不会改变。缩放、调整浏览器窗口改变的只是 visual viewport。

在桌面浏览器中,缩放100% 的时候,Layout Viewport 宽度等于内容窗口的宽度。(你几乎不会在电脑上见过横向滚动条,除非你调整缩放

但是在移动端,缩放为 100% 的时候,Layout Viewport 不一定等于内容窗口的大小。当你用手机浏览浏览宽大的网页(这些网页没有采用响应式设计)的时候,你只能一次浏览网页的一个部分,然后通过手指滑动浏览其他部分。这就说明整个网页已经加载出来了,只不过你要一部分一部分地看。

  1. visual viewport

visual viewport 为视觉视口,就是显示在屏幕上的网页区域 ,它往往只显示 layout viewport 的一部分 visual viewport 就像一台摄像机,layout viewport 就像一张纸,摄像机对准纸的哪个部分,你就能看见哪个部分。你可以改变摄像机的拍摄区域大小(调整浏览器窗口大小 ),也可以调整摄像机的距离(调整缩放比例),这些方法都可以改变 visual viewport,但 layout viewport 始终不变

  1. ideal viewport

ideal viewport 为理想视口,不同的设备有自己不同的 ideal viewport,ideal viewport 的宽度等于移动设备的屏幕宽度,所以其是最适合移动设备的 viewport。只要在 css 中把某一元素的宽度设为 ideal viewport 的宽度(单位用 px ),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100% 的效果。 ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。

利用 meta 标签控制 viewport

移动设备默认的是 layout viewport ,也就是那个比屏幕要宽的 viewport,但在进行移动端 H5 的开发时,我们需要的是 ideal viewport 。那么怎么才能得到 ideal viewport 呢?

我们在开发 h5 页面时,最经常见的标签如下所示

html 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

该 meta 标签的作用是让当前 viewport 的宽度等于设备的宽度,同时不允许用户手动缩放 。如果你不这样的设定的话,那就会使用那个比屏幕宽的默认 viewport(layout viewport),也就是说会出现横向滚动条。

相关的属性意义如下所示:

width 设置 layout viewport 的宽度,为一个正整数,或字符串 "width-device"
height 设置页面的初始缩放值,为一个数字,可以带小数
initial-scale 允许用户的最小缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最大缩放值,为一个数字,可以带小数
maximum-scale 设置 layout viewport 的高度,这个属性对我们并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes 代表允许

对比

页面在桌面端的预览效果

在移动端的预览效果【左图没有设置 viewport,右图设置了 viewport】

媒体查询 @media

媒体查询是 CSS3 中的一项特性,允许我们根据设备的特定条件(如窗口或视口的宽度、高度、设备的方向、分辨率等)来应用不同的样式。这使得我们的网页在各种设备(桌面电脑、平板、手机等)和窗口大小上都有良好的显示和交互体验,也就是响应式设计的关键。

一个基本的媒体查询语法如下:

css 复制代码
@media media_type and (media_feature) {
  /* 匹配时的 CSS 样式 */
}

其中:

  • media_type 是目标媒体设备的类型,如 screen, print 等。如果你不指定媒体类型,那意味着应用到所有媒体类型上(也就是 all)。
  • media_feature 是特定的设备特性,如 width, height等。
  • and 用于将多个媒体特性合并在一起,所有条件必须匹配,样式才会被应用。

媒体查询的具体使用可以查阅我之前写的文章:CSS系列 -- 媒体查询,在此不作赘述

自适应单位

自适应单位包括 remvw 和百分比%

rem 单位

rem 是根据 根元素(html)字体大小 变化的相对单位。 rem 的全名是 root em ,其值是相对于根元素的字体大小计算的。这意味着调整根元素的字体大小后,所有使用 rem 单位的元素都会自动调整。介绍如下:

  1. rem 是基于根元素(即 html 元素)字体大小计算的
  2. 计算公式:1 rem = 根元素字体大小

示例:

HTML 复制代码
<!DOCTYPE html>
<html>
  <head>
    <style>
      html {
        font - size: 16px;
      }
      p {
        font - size: 1.25rem;
      }
    </style>
  </head>
  <body>
    <p>Hello, World!</p>
  </body>
</html>

在这个例子中,通过设置根元素字体大小为 16px,并为 <p> 元素设置颜色值为 1.25rem,计算出 <p> 的字体大小为 (16 * 1.25)px = 20px

vw、vh 单位

vw 是基于视口宽度 的相对单位,vh 则是基于视口高度的相对单位。

视口的定义:web 页面能渲染的地方

其中 vwviewport width 的缩写。vw 单位是基于浏览器窗口宽度的相对度量,可以让元素自适应调整,无论设备大小。介绍如下:

  1. vw 是基于视口的宽度计算的
  2. 计算公式:1 vw = 视口宽度的1%

示例:

CSS 复制代码
div {
  width: 50vw;
}

在这个例子中,将 <div> 的宽度设置为视口宽度的一半,即 50vw。如果视口宽度为 1200px<div> 的宽度为 (1200 * 50/100)px = 600px

rem 和 vw 的区别

  • "rem" 更适合用于字体大小、间距、边框等相对比较小的元素,因为这些元素大小的变化相对不会太大
  • "vw" 更适合用于相对于视口宽度而言较大的元素,例如页面的宽度或高度、容器的宽度

百分比 % 单位

百分比单位%是相对于其父元素的尺寸来定义的。这意味着元素会根据其父元素的尺寸变化。这种单位充分利用了可用空间,可以实现自适应设计。介绍如下:

  1. % 是基于父元素的尺寸计算的
  2. 计算公式:1% = 父元素尺寸的1%

示例:

HTML 复制代码
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        width: 800px;
      }
      div {
        width: 50%;
      }
    </style>
  </head>
  <body>
    <div>Hello, World!</div>
  </body>
</html>

在这个例子中,将 <div> 的宽度设置为其父元素(<body>)宽度的一半,即 50%。因此 <div> 的实际宽度是其父元素宽度的一半:(800 * 50/100)px = 400px

px 自动转换为 vw

设计师经常给宽度大小为 375px 或 750px 的视觉稿,单位是 px,手动转换起来就很头疼,所以可以采用社区提供的 postcss-px-to-viewport 插件,可以实现将单位 px 自动转换为 vw

  1. 安装插件
bash 复制代码
npm install postcss-px-to-viewport --save-dev
yarn add -D postcss-px-to-viewport
  1. 引入插件

我们项目用的是 React 框架 + umi 脚手架,所以参考 umi 官网文档 - API 之配置,使用 extraPostCSSPlugins 这个属性即可引入 postcss-px-to-viewport 插件

  1. 参数配置

参数配置示例:(其他配置项参考官网)

js 复制代码
import px2vw from 'postcss-px-to-viewport';

export default defineConfig({
  extraPostCSSPlugins: [
    px2vw({
      unitToConvert: 'px', // 要转化的单位
      viewportWidth: 750, // 视窗的宽度,可根据自己的需求调整(这里是以PC端为例)
      // viewportHeight: 1080, 		// 视窗的高度
      unitPrecision: 6, // 转换后的精度,即小数点位数
      propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
      viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
      fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
      // selectorBlackList: ['wrap'],// 指定不转换为视窗单位的类名,
      minPixelValue: 0.1, // 默认值1,小于或等于1px则不进行转换
      mediaQuery: false, // 是否在媒体查询的css代码中也进行转换,默认false
      replace: true, // 是否转换后直接更换属性值
      exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
      landscape: false, // 是否处理横屏情况
    }),
  ]
});
  1. 最终效果
less 复制代码
.invalid {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: -80px;
  left: 0;
  font-size: 32px;
}

响应式布局

flex 布局

参考 flex 布局的基本概念 - MDN 提供的定义:Flexible Box 模型 ,通常被称为 flexbox,是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布对齐能力 。我们说 flexbox 是一种一维的布局,是因为一个 flexbox 一次只能处理一个维度上的元素布局,一行或者一列

flex 布局的使用可以查阅我以前写的文章:CSS系列 -- flex布局,在此不作赘述

grid 布局

参考 网格布局 - MDN 提供的定义:CSS 网格布局 擅长于将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。像表格一样,网格布局让我们能够按行或列来对齐元素。然而在布局上,网格比表格更可能做到或更简单。例如,网格容器的子元素可以自己定位,以便它们像 CSS 定位的元素一样,真正的有重叠和层次。

grid 布局的使用也可以查阅我以前写的文章:CSS系列 -- grid布局,在此不作赘述

模拟设备测试方案

模拟桌面端屏幕尺寸

  1. 打开 Chrome 浏览器控制台,打开设备工具栏(Ctrl+Shift+M)
  1. 打开尺寸栏,选择【自适应】,拖动右下角即可随意设置屏幕尺寸宽高,模拟各种桌面端屏幕尺寸非常地简单。同时也可以直接输入宽高,更加精确

模拟移动端设备

为了模拟多端设备的纵横比,同样可以利用控制台来模拟这些设备

  1. 打开尺寸栏,点击【修改】
  1. 填写设备信息
  1. 保存设备后即可快速模拟各端的纵横比(这里只举例三个)

H5 会变"矮"?

细心的同学会发现:真机测试时在大多数移动端浏览器和 APP 端内打开的 H5 会变"矮"

这是由于大多数移动端浏览器和 APP 端内有固定高度的状态栏、标题栏、底部导航栏 ,影响了视口高度 ,所以在真机中打开的 H5 的纵横比要实际小于 上面计算出的纵横比,所以我们也要考虑到状态栏、标题栏、底部导航栏占掉的高度(特别是有一屏渲染的需求)

这里我推荐下载安装 微信开发者工具 来模拟真机效果

  1. 下载安装后打开微信开发者工具,选择公众号网页项目
  1. 把本地 dev 运行的链接直接贴进去,即可同时看到控制台打印信息和模拟器
  1. 自定义模拟器

同样的,我们也可以自定义模拟器的配置

可以看到,所有的模拟器状态栏标题栏都占用了 H5 的高度

而且当我们选择 iPhone X 及以上的苹果系统设备 模拟器时,还有苹果系统自带的底部安全区占用了 H5 的高度

不同的是:

  • 状态栏和标题栏"挤掉"了 H5 的高度
  • 苹果系统自带的底部安全区没有占用 H5 的高度,而是"覆盖"在 H5 上面的,所以我们要给 iPhone X 及以上的苹果系统留足一定的安全距离

值得一提的是:

  • 安卓系统真机自带的底部导航栏 也会"挤掉" H5 的高度(这在微信开发者工具的模拟器没有出现),所以不需要 H5 本身去兼容,只需要考虑到高度会变"矮"的情况即可

H5 给苹果系统留足安全距离

苹果系统中的一个可视窗口范围,受圆角、齐刘海、小黑条 影响,下图的蓝色区域才是 H5 (当然也包括 APP)的可操作区域:

也就是说,我们必须要保证页面可视、可操作区域到屏幕边界有一定的安全距离 。更详细说明参考文档:Human Interface Guidelines - iPhoneX

先了解:viewport-fit 属性

iOS11 新增特性,苹果公司为了适配 iPhoneX 对现有 viewport meta 标签的一个扩展,用于设置网页在可视窗口的布局方式,可设置三个值。

  • contain: 可视窗口完全包含网页内容(左图)
  • cover:网页内容完全覆盖可视窗口(右图)
  • auto:默认值,跟 contain 表现一致

需要注意:网页默认不添加扩展的表现是 viewport-fit=contain,需要适配 iPhoneX 必须设置 viewport-fit=cover,这是适配的关键步骤。更详细说明,参考文档:viewport-fit-descriptor

先了解:env()、constant() 函数

iOS11 新增特性,Webkit 的一个 CSS 函数,用于设定安全区域与边界的距离,有四个预定义的变量:

  • safe-area-inset-left:安全区域距离左边边界距离
  • safe-area-inset-right:安全区域距离右边边界距离
  • safe-area-inset-top:安全区域距离顶部边界距离
  • safe-area-inset-bottom:安全区域距离底部边界距离

这里我们只需要关注 safe-area-inset-bottom 这个变量,因为它对应的就是小黑条的高度(横竖屏时值不一样)。

注意:当 viewport-fit=contain 时 env() 是不起作用的,必须要配合 viewport-fit=cover 使用。对于不支持 env() 的浏览器,浏览器将会忽略它

需要注意的是之前使用的 constant() 在 iOS11.2 之后就不能使用的,但我们还是需要做向后兼容,像这样:

css 复制代码
padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */

注意:env() 跟 constant() 需要同时存在而且顺序不能换 。 更详细说明,参考文档:Designing Websites for iPhone X

方案

  1. 新增 viweport-fit 属性,使得页面内容完全覆盖整个窗口
html 复制代码
<meta name="viewport" content="width=device-width, viewport-fit=cover">
  1. 通过加内边距 padding 扩展高度:
css 复制代码
{
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

注意,这个方案需要吸底条必须是有背景色的,因为扩展的部分背景是跟随外容器的,否则出现镂空情况。

还有一种方案就是,可以通过新增一个新的元素空的颜色块,主要用于小黑条高度的占位),然后吸底元素可以不改变高度只需要调整位置,像这样:

css 复制代码
{
  margin-bottom: constant(safe-area-inset-bottom);
  margin-bottom: env(safe-area-inset-bottom);
}

空的颜色块:

css 复制代码
{
  position: fixed;
  bottom: 0;
  width: 100%;
  height: constant(safe-area-inset-bottom);
  height: env(safe-area-inset-bottom);
  background-color: #fff;
}

参考文章

相关推荐
王解30 分钟前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁34 分钟前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂39 分钟前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑2136 小时前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy6 小时前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js