CSS视口单位动态计算:浏览器UI栏收缩对`dvh`与`svh`的实时重算

CSS 视口单位动态计算:浏览器 UI 栏收缩对 dvhsvh 的实时重算

大家好,今天我们来深入探讨一个在现代 Web 开发中日益重要的主题:CSS 视口单位的动态计算,特别是当浏览器 UI 栏(如地址栏、底部导航栏等)收缩或展开时,dvhsvh 这两个单位的实时重算。

什么是视口单位?

在讨论 dvhsvh 之前,我们先回顾一下 CSS 中常见的视口单位:

  • vw (viewport width): 视口宽度的 1%。
  • vh (viewport height): 视口高度的 1%。
  • vi (viewport inline size): 视口内联尺寸的 1%。 在水平书写模式下,等同于 vw
  • vb (viewport block size): 视口块尺寸的 1%。 在水平书写模式下,等同于 vh
  • vmin (viewport minimum): 视口宽度和高度中较小值的 1%。
  • vmax (viewport maximum): 视口宽度和高度中较大值的 1%。

这些单位提供了一种相对于浏览器视口大小来设置元素大小的方式,使得布局更加灵活和响应式。然而,传统的 vh 单位存在一个问题:它基于视口初始高度计算,不考虑动态变化的浏览器 UI 栏。这意味着当用户滚动页面,UI 栏收缩时,使用 vh 单位设置的元素高度可能超出实际可见区域,导致内容被遮挡。

dvhsvh:更智能的视口高度单位

为了解决 vh 的局限性,CSS 引入了 dvh (dynamic viewport height) 和 svh (small viewport height) 这两个新的视口高度单位。

  • dvh (dynamic viewport height): 动态视口高度的 1%。它会随着浏览器 UI 栏的显示和隐藏而动态调整,始终反映当前可见视口的最大高度。
  • svh (small viewport height): 最小视口高度的 1%。它基于 UI 栏完全展开时的视口高度计算,代表了当前环境下的最小可用视口高度。

dvhsvh 之间的关系可以用以下表格概括:

单位 描述 适用场景
vh 视口初始高度的 1% 适用于不需要考虑浏览器 UI 栏动态变化的场景,或者在不支持 dvhsvh 的旧浏览器中作为回退方案。
dvh 动态视口最大高度的 1% 适用于需要占据整个可见视口,并随着浏览器 UI 栏变化而动态调整的元素,例如全屏背景、固定定位的元素等。
svh UI 栏完全展开时视口高度(最小高度)的 1% 适用于需要确保元素始终在最小可用视口内可见的场景,例如在移动设备上,防止内容被底部导航栏遮挡。
lvh 逻辑视口最大高度的 1% 适用于逻辑像素计算的视口,和dvh类似,但主要区分逻辑像素和物理像素。

除了dvhsvh外,还有lvh等逻辑视口单位,他们和dvh的区别主要在于计算的逻辑像素而不是物理像素。

浏览器 UI 栏收缩对 dvhsvh 的影响

当浏览器 UI 栏收缩时,dvh 的值会增大,因为它反映了当前可见视口的最大高度。而 svh 的值保持不变,因为它基于 UI 栏完全展开时的视口高度计算。

以下面的例子说明:

假设初始视口高度(UI 栏完全展开)为 800px,UI 栏收缩后的视口高度为 900px。

  • 100vh 始终等于 800px。
  • 100dvh 在 UI 栏展开时等于 800px,在 UI 栏收缩时等于 900px。
  • 100svh 始终等于 800px。

如何使用 dvhsvh

在 CSS 中,你可以像使用其他视口单位一样使用 dvhsvh。例如:

.full-height-element {
  height: 100dvh; /* 占据整个可见视口的高度,并随着 UI 栏变化而动态调整 */
}

.safe-area-element {
  height: 100svh; /* 确保元素始终在最小可用视口内可见 */
}

dvhsvh 的实际应用场景

  • 全屏背景: 使用 height: 100dvh 可以创建一个占据整个可见视口的背景,即使浏览器 UI 栏收缩,背景也能始终覆盖整个屏幕。

    .full-screen-background {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100dvh;
      background-image: url("your-image.jpg");
      background-size: cover;
      z-index: -1; /* 将背景放在内容后面 */
    }
  • 固定定位的页眉/页脚: 使用 height: 100dvhheight: 100svh 可以确保固定定位的页眉或页脚始终占据正确的视口高度,不会被浏览器 UI 栏遮挡。

    .header {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 10vh; /* 或者使用固定像素值 */
      background-color: #fff;
      z-index: 10;
    }
    
    .footer {
      position: fixed;
      bottom: 0;
      left: 0;
      width: 100vw;
      height: 10svh; /* 确保底部导航栏不会遮挡页脚 */
      background-color: #fff;
      z-index: 10;
    }
    
    .content {
      margin-top: 10vh; /* 为页眉留出空间 */
      margin-bottom: 10svh; /* 为页脚留出空间 */
    }
  • 移动应用中的安全区域: 在移动应用中,可以使用 height: 100svh 来确保内容始终在安全区域内可见,防止被状态栏、导航栏或其他 UI 元素遮挡。

    .safe-area {
      padding-top: env(safe-area-inset-top); /* 使用环境变量获取安全区域的内边距 */
      padding-bottom: env(safe-area-inset-bottom);
      height: 100svh;
    }
  • 模态框/对话框: 使用dvh可以设置模态框的高度,确保在UI栏变化时,模态框始终占据整个可见视口,提供更好的用户体验。

    .modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100dvh;
      background-color: rgba(0, 0, 0, 0.5); /* 半透明背景 */
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 1000;
    }
    
    .modal-content {
      background-color: #fff;
      padding: 20px;
      border-radius: 5px;
    }

dvhsvh 的兼容性

截至目前(2024年),dvhsvh 的兼容性已经相当不错,主流浏览器都支持这些单位。然而,为了确保在旧浏览器中的兼容性,建议使用 vh 作为回退方案,并使用 CSS 的 @supports 特性查询来判断浏览器是否支持 dvhsvh

.full-height-element {
  height: 100vh; /* 回退方案 */
}

@supports (height: 100dvh) {
  .full-height-element {
    height: 100dvh; /* 支持 dvh 的浏览器使用 dvh */
  }
}

.safe-area-element {
  height: 100vh; /* 回退方案 */
}

@supports (height: 100svh) {
  .safe-area-element {
    height: 100svh; /* 支持 svh 的浏览器使用 svh */
  }
}

或者,可以使用 JavaScript 来检测 dvhsvh 的支持情况,并动态地更新 CSS 变量。

function supportsDvhSvh() {
  return CSS.supports('height', '100dvh') && CSS.supports('height', '100svh');
}

if (supportsDvhSvh()) {
  console.log('dvh and svh are supported!');
} else {
  console.log('dvh and svh are not supported.');
  // 提供回退方案,例如使用 vh 或者 JavaScript 来计算高度
}

使用 JavaScript 监听视口变化并动态调整

即使浏览器支持 dvhsvh,有时也可能需要使用 JavaScript 来监听视口变化,并根据需要动态调整元素的大小。例如,你可能需要根据设备的屏幕方向、键盘的显示状态或其他因素来调整布局。

可以使用 ResizeObserver API 来监听元素大小的变化,包括视口大小的变化。

const resizeObserver = new ResizeObserver(entries => {
  for (let entry of entries) {
    const viewportHeight = window.innerHeight;
    document.documentElement.style.setProperty('--viewport-height', `${viewportHeight}px`);
  }
});

resizeObserver.observe(document.documentElement); // 监听根元素的大小变化

// 在 CSS 中使用 CSS 变量
/*
.element {
  height: var(--viewport-height);
}
*/

在这个例子中,我们创建了一个 ResizeObserver 实例,并监听根元素(document.documentElement)的大小变化。当视口大小发生变化时,ResizeObserver 会触发回调函数,我们可以在回调函数中获取当前视口的高度,并将其设置为 CSS 变量。然后,我们可以在 CSS 中使用这个 CSS 变量来设置元素的高度。

潜在问题和注意事项

  • 过度使用 dvh: 虽然 dvh 很有用,但过度使用可能会导致布局不稳定,因为元素的大小会随着浏览器 UI 栏的变化而不断调整。 谨慎使用,并确保布局在各种情况下都能正常工作。

  • 性能问题: 频繁地计算和更新元素的大小可能会影响性能,特别是在复杂的布局中。 尽量减少不必要的计算,并使用性能分析工具来优化代码。

  • 与其他 CSS 属性的冲突: dvhsvh 可能会与其他 CSS 属性(如 min-heightmax-height 等)发生冲突。 确保理解这些属性之间的优先级关系,并避免出现意外的结果。

  • overflow 属性: 在使用 dvh 设置元素高度时,需要注意 overflow 属性的设置。 如果元素的内容超出其高度,可能会导致内容被裁剪或出现滚动条。

总结一下

dvhsvh 是 CSS 中非常有用的视口高度单位,可以帮助我们创建更加灵活和响应式的布局,特别是当需要考虑浏览器 UI 栏的动态变化时。 通过充分理解这些单位的特性和使用场景,我们可以构建更好的用户体验。记住,兼容性是关键,务必提供合理的降级方案。

兼容性与优雅降级策略

确保你的代码能够在各种浏览器环境下正常运行,为不支持 dvhsvh 的浏览器提供回退方案。

考虑性能影响

避免过度使用 dvhsvh,特别是在复杂的布局中。 使用性能分析工具来优化代码,确保页面流畅运行。

动态调整需要谨慎

虽然 JavaScript 可以动态调整元素的大小,但也需要谨慎使用,避免出现布局抖动或性能问题。

更多IT精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注