前言

当我们想要将一个元素高度设置为全屏(整个视窗)高度时,经常使用以下代码:

.element {
    height: 100vh;
}

以上在 PC 上没有任何问题,问题主要出现在移动端。由于移动端屏幕尺寸小,寸土寸金,有些厂商(如 iOS Safari)会有特殊的处理(或者说是 bug)。Safari 上只在必要时才显示工具栏,尽可能给网站更多的空间,这就是为什么在滚动时工具栏会自动隐藏。这导致了处理视窗高度时出现问题:

  • 每次工具栏隐藏和显示时视窗高度会改变;
  • 工具栏会遮挡视窗的一部分。

问题说明

1_1659529780_uRG36QjkCm.png

例如一个常规的网站布局,header 固定在顶部(sticky 或者 fixed 均可)。左侧是导航目录,高度为 视窗高度 - header 高度。右侧为内容区。如果我们将左侧导航目录高度设置为 100vh - header 高度,就会出现工具栏遮挡导航目录的问题,滚动条滚动到底部了,仍有一部分内容被工具栏遮挡。

如何解决这个问题呢?比较简单的就是使用 JavaScript 动态获取视窗高度。视窗高度变化时,更新导航目录高度。

解决方案

处理思路如下:

  1. 页面加载后,获取视窗高度,更新导航目录高度;
  2. 监听窗口 resize 事件,触发时,重新更新导航目录高度。

为了方便更新导航目录高度,我们使用 css 变量。

// 定义一个视窗高度变量
:root {
    --i-window-height: 100vh;
}

// 设置导航目录高度,header 高度为 4rem
.sidebar {
    height: calc(var(--i-window-height) - 4rem);
}

接下来只需要更新 --i-window-height 就可以了。

在 Vue3 中实现代码如下:

<script setup>
import { onBeforeUnmount, onMounted } from "vue";

function updateWindowHeight() {
    let windowHeight = window.innerHeight;
    let html = document.querySelector(":root");
    if (windowHeight > 0 && html) {
        html.style.setProperty("--i-window-height", `${windowHeight}px`);
    }
}

onMounted(() => {
    updateWindowHeight();
    on(window, "resize", updateWindowHeight);
});

onBeforeUnmount(() => {
    off(window, "resize", updateWindowHeight);
});
</script>

参考资料: