苹果浏览器Bug惹怒设计师,三个新CSS单位破局,移动端布局再无难题!

286 阅读5分钟

我们自2012年以来就一直在使用CSS视口单位。它们用于根据视口宽度或高度调整元素大小非常有用。

然而,在移动设备上使用vh单位存在问题。原因是视口大小不会包括浏览器的地址栏UI。 

为了解决这个问题,我们现在有了新的视口单位。

CSS视口单位

例如,当我们需要根据视口大小调整元素大小时,视口单位有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的收缩,动态视口单位将发生改变。这里有一个视频展示了动态视口的变化:

用例和例子

带粘性头部和底部的模态框

图片

在这个例子中,我们有一个带有粘性头部和底部的模态框。如果内容够长,中间部分应该可以滚动。这个例子的灵感来自Max Schmitt在研究该主题时的一个图表。

考虑以下CSS:

.modal {  
    position: fixed;  
    top: 0;
    left: 0;
    right: 0;
    height: 100vh;
   }

使用100vh会使模态框的底部不可见。在示例中,这意味着页脚将不可见,这将破坏UX。

以下是传统和新视口单位在iOS上的显示效果:

图片

..以及Android上的Chrome和Firefox:

图片

为了解决这个问题,我们可以使用svh或dvh单位。

这里有一个视频展示了dvh和vh之间的区别。

英雄区域

图片****

常见的一个案例是需要将英雄区域的高度设置为等于完整视口高度减去头部高度。在像iOS Safari和Android上的Firefox和Chrome这样在滚动时收缩其UI的浏览器上,使用传统的vh会导致失败。

首先,我们需要确保头部高度是固定的。我使用了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浏览器中被裁切。

以下是svh和vh在Safari iOS上的比较。

图片

..以及Android上的Chrome和Firefox:

图片

请观看以下视频,并注意使用svh和vh之间的区别。

在这种情况下,使用svh将解决问题。

是否有可能将Dvh设为默认单位?

起初,答案是“是的,为什么不呢?”。然后我想了想,dvh的值在滚动时会改变,所以在字体大小等方面使用它可能会造成困惑。

h1 {  font-size: calc(1rem + 5dvh); }

图片

小心使用Dvh视口单位

动态视口单位可能会影响页面性能,因为当用户向上或向下滚动时,浏览器需要大量重新计算样式。

我没有机会进行密集的性能测试,但我会谨慎使用它。希望我能在这里找到时间进行更新。

新视口单位也有用的其他地方

这些新的视口单位可能不仅仅关乎移动浏览器。事实上,你现在可以在电视上浏览网页。谁知道什么浏览器会用于一个在滚动时改变UI并调整视口大小的电视?

例如,这里是在Android TV上查看的英雄区域示例:

图片

它可以完美工作,即使我们有一个动态UI也能继续工作。

最后

标题有点太标题党了,我知道,因为我是用Claude帮我生成的标题,比我自己想的还要夸张,所以用来试试

image.png

【公众号:H5talks】