本文为翻译
本文译者为 360 奇舞团前端开发工程师
原文标题:New Viewport Units
原文作者:Ahmad Shadeed
原文地址:https://ishadeed.com/article/new-viewport-units/
自 2012 年以来,我们一直在使用 CSS viewport 单位。它们对于帮助我们根据视口宽度或高度调整元素大小很有用。
然而,在移动设备上使用 vh 单位是有问题的。原因是视口大小不包括浏览器的地址栏 UI。
为了解决这个问题,我们现在有了新的视口单位。让我们在这篇文章中了解一下它们。
CSS Viewport单位
例如,当我们需要根据视口大小调整元素的大小时。视口单位为 vw、vh、vmin 和 vmax。
考虑下图:

值 50vw 的意思是:给元素一个等于视口宽度 50% 的宽度。
问题
当使用 100vh 调整元素大小以占据移动端视口的全部高度时,它将大于顶部和底部栏之间的空间。这种情况会发生在滚动时缩小 UI 的浏览器中,例如 Android 上的 Safari 或 Chrome。
下图显示了每个移动浏览器的顶部和底部UI是如何不同的。


假设我们有一个充满整个屏幕的加载视图。
/* 我知道我们可以使用bottom: 0代替height: 100vh,但这里是故意突出这个问题。 */
.loading-wrapper {
position: fixed;
left: 0;
right: 0;
top: 0;
height: 100vh;
display: grid;
place-items: center;
}
考虑下图:

加载图标在 CSS 中居中,但从视觉上看,它看起来稍微位于底部。为什么会发生这种情况?

对于浏览器来说,height: 100vh 意味着元素将填充视口高度,但它不会动态的计算值。这意味着底部地址栏和工具栏不会被计算。
因此,我们期望 100vh 等于从视口顶部到地址栏 UI 顶部。

当我们向下滚动时,地址栏 UI 将缩小其尺寸。这很好,因为它为用户提供了更多的垂直空间来浏览页面。与此同时,它也在某种程度上破坏了 UI。
在下图中,当地址栏可见时,垂直空间的中心不符合预期。滚动时,看起来不错。

注意我是如何突出显示不可见区域的。当向下滚动时,它变得可见。如何在CSS中处理这个问题?
小、大和动态视口单位
为了解决这个问题,CSS 工作组同意采用一组新的单位:svh、lvh 和 dvh。它们分别代表小视口、大视口和动态视口。

小视口
svh 表示地址栏 UI 尚未缩小尺寸时的视口高度。

大视口
lvh 表示地址栏 UI 缩小尺寸后的视口高度。

动态视口
从名字上看,这个单位是动态的。这意味着它将根据地址栏 UI 是否缩小而使用小的、中间的和大的单位。

在初始滚动期间,动态视口单位将随着浏览器 UI 的收缩而改变。这是一个展示动态视口变化的视频:

用例和示例
具有粘性页眉和页脚的弹窗

在这个例子中,我们有一个带有粘性页眉和页脚的弹窗。如果内容足够长,中间部分应该滚动。
考虑以下 CSS:
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100vh;
}
使用 100vh 将使弹窗的底部部分不可见。在示例中,这意味着页脚将不可见,这将破坏用户体验。
以下是 iOS 上传统和新视口单位的表现:

..加上 Android 上的 Chrome 和 Firefox:

为了解决这个问题,我们可以使用 svh 或 dvh 单位。
这是一个视频,显示了 dvh 和 vh 之间的差异。

主页横幅

这是一种常见的情况,我们需要使主页横幅的高度等于整个视口高度减去标题高度。在这种情况下,使用传统的 vh 在 iOS Safari、Firefox 和 Android 版 Chrome 等会在滚动时缩小 UI 的浏览器中会失败。
首先,我们需要确保标题高度是固定的。我为此使用了 min-height。
:root {
--header-height: 60px;
}
.site-header {
position: sticky;
top: 0;
min-height: var(--header-height, initial);
}
之后,我将 min-height 添加到主页横幅并使用 calc()。
.hero {
min-height: calc(100svh - var(--header-height));
}
使用 vh 时,装饰元素(紫色)根本不可见。事实上,如果你仔细观察,你会发现它模糊的显示在 iOS Safari 中的地址栏 UI 下方,而在 Android 浏览器中则被裁剪掉了。
以下是 Safari iOS 上 svh 和 vh 的比较。

..加上 Android 上的 Chrome 和 Firefox:

请观看以下视频并找出使用 svh 和 vh 之间的区别。

在这种情况下,使用svh就可以解决问题。
是否可以将 Dvh 设置为默认单位?
起初,答案是“是的,为什么不呢?”。然后我想,dvh 值会随着你滚动而改变,所以当它用于诸如 font-size 之类的东西时,可能会产生一种令人困惑的体验。
h1 {
font-size: calc(1rem + 5dvh);
}

观看以下视频,注意地址栏 UI 缩小后字体大小如何变化:

Demo
小心使用 Dvh 视口单位
动态视口单位可能会影响页面的性能,因为浏览器需要花费大量工作来重新计算用户向上或向下滚动的样式。
我没有机会进行密集的性能测试,但使用时我会小心。我希望我能有时间在这里更新这一点。
新视口单位有用的其他地方
这些新的视口单位可能不仅仅适用于移动浏览器。事实上,你现在可以在电视上浏览网页。谁知道电视上会出现哪种浏览器,其 UI 会在滚动时发生变化,从而调整视口的大小?
例如,以下是在 Android TV 上查看的主页横幅示例:

效果很好,即是动态 UI 也能继续生效。
- END -
关于奇舞团
奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。