CSS Pioneer: 最新 viewport 尺寸单位 lvh, svh, dvh ... *v* —— 适配移动端浏览器工具栏伸缩不再是梦

2,198 阅读3分钟

太长不看 (TL;DR)

  • CSS 迎来数个新相对 viewport 的尺寸单位——其中 lvwsvwdvw 分别代表“大视窗宽度百分比”、“小视窗宽度百分比”、“动态视窗宽度百分比”;viewport 高度百分比尺寸同理。
  • “大视窗”、“小视窗”分别代表浏览器“工具栏收起”、“工具栏展开”场景下的视窗;“动态视窗”则代表跟随浏览器工具栏尺寸变化的实时视窗大小。

正文

温馨提示:对 vwvhviewport 概念不熟悉的同学请先自行补课。

相信很多小伙伴遇到过写“全屏页面”的需求。桌面端好说——直接 width: 100vwheight: 100vh 就行。但到了移动端,事情就没这么简单了——移动端浏览器的 视窗viewport 大小会动态变化。

以 Safari (iOS 16.0.2) 为例,新开页面时页面底部工具栏很明显,此时工具栏最大化展开,视窗为小视窗small viewport;当滚动距离超过阈值后,工具栏会进入最小化状态,此时视窗为大视窗large viewport

Safari 浏览器工具栏最大化时的截屏 Safari 浏览器工具栏最小化时的截屏

这里不方便传视频,对此特性不熟悉的同学建议拿出手机自行感受一下。

W3C 在 CSS Values and Units Module Level 3 及之前的标准中 vwvh 等相对视窗尺寸为“响应变化的初始包含块的尺寸”,并没有规定最大、最小的视窗尺寸。而在 Level 4 中,W3C 对此做了定义:

  1. lv* 开头的尺寸单位是相对于“大视窗”(工具栏收起)的 1%,浏览器尺寸不变时是个固定值
  2. sv* 开头的尺寸单位是相对于“小视窗”(工具栏展开)的 1%,浏览器尺寸不变时是个固定值
  3. dv* 开头的尺寸单位是相对于“当前视窗”大小的 1%
  4. v* 开头的尺寸单位相对于的视窗尺寸要介于“大视窗”和“小视窗”之间,单位长度为视窗尺寸的 1%(此标准尚有争议)

上述前缀适用于 vw, vh, vmin, vmax 等各种视窗相对百分比单位。

在 Safari (iOS 16.0.2) 测试一下可以发现:小视窗时 100svh 刚好填充屏幕,大视窗时 100lvh 刚好填充屏幕,而 100dvh 则与当前视窗尺寸保持一致。(代码见附录)

不过看起来还有问题:工具栏的背景颜色应该是模糊红色(蒙层覆盖在 100lvh 之上),但上图小视窗截图里看来并没有模糊。这个问题我记得之前也遇到过,后续有时间再学习一下。

兼容性

根据 Can I Use 的数据(源自 MDN browser-compat-data),截止到2022年11月21日,全球仅有约 18% 的浏览器支持了相关属性。

截屏2022-11-21 02.19.25.png

BTW

现在,相对视窗百分比尺寸单位有了前缀 lv*, sv* 等,有了后缀 *vw, *vh 等,所以所有相关尺寸都可以简写为 *v* —— 一张可爱的笑脸诞生啦~

所以我宣布,这么好用的单位,以后一律叫可爱单位!*v*

附录:新单位测试代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Demo - CSS Values and Units Module Level 4</title>
</head>

<style>
  body { margin: 0; height: 200vh }
  .vh {
    width: 100vw;
    position: fixed;
    top: 0;
    left: 0;
    display: flex;
    align-items: flex-end;
    color: #fff;
  }
  #lvh { height: 100lvh; z-index: 1; background-color: #700 }
  #svh { height: 100svh; z-index: 2; background-color: #070 }
  #dvh { height: 100dvh; z-index: 3; justify-content: flex-end }
</style>

<body>
  <div class="vh" id="lvh">100lvh</div>
  <div class="vh" id="svh">100svh</div>
  <div class="vh" id="dvh">100dvh</div>
</body>

</html>