[译] 解决 100vw 下滚动条引发的问题

7,588 阅读4分钟

原文链接:Scrollbars & CSS Custom Properties,by  Louis Hoebregts

Photo by Maria Teneva on Unsplash

摘要

  • Widows 系统中的滚动条是会占据视口空间的。
  • vw 单位没有将滚动条计算在内。
  • fixed 弹出框里的 fixed 按钮是相对视口定位的而非弹出框。

正文

作为一个 Windows 系统用户,我有时会注意到有些网站没有在 Windows 上测试。导致的问题之一就是,可能在什么地方会看见一个滚动条没有理由的出现!在 MacOs 系统中,当你不滚动页面是,滚动条默认是隐藏的。它们也不占据任何的视口空间,这就表示 100% 的 body 宽度等于 100% 的屏幕宽度。但是在 Windows 系统中,滚动条的宽度会从窗口的宽度中减掉。不提供的浏览器的滚动条宽度有所差异,但通常是 17px 宽。

这里列出了我最近遇到的两个情况:

1. 在使用 vm 单位时

规范 中对 vw 单位的定义如下:

视口百分比长度(viewport-percentage lengths)是相对于初始包含块(viewport-percentage lengths)的尺寸计算的。[...] 但是,我们假设滚动条是不存在的。

说的很清楚了,滚动条是不会影响 vw 单位计算的。

下面的截屏中,div 的宽度设置成了 100vw。可以看见,因为垂直滚动条的存在,有两个问题。

首先,因为 div 太宽了,把横向滚动条戳出来了;其次,因为有垂直滚动条出现,在没有滚动横向滚动条的默认情况下,段落文本被滚动条覆盖裁剪了。

.container {
  width: 100vw;
}

2. 在使用 fixed 弹出框时

我在实现弹出框的时候,通常会为弹出框指定一个宽度还有 overflow: auto; 样式。这样,如果弹出框里的内容很多,用户可以滚动内容。但是用户也可以使用关闭按钮关闭弹框,但我希望滚动的时候关闭按钮也是可见的。因此,在弹出框中我将关闭按钮 position: fixed; 了。

下面是我想实现的效果。在没有出现滚动条的时候,一切正常。

这是关闭按钮使用的样式:

.close {
  position: fixed;
  top: 40px;
  right: 40px;
}

当弹框内容很多时。滚动条出现,此时关闭按钮的对齐就不是很完美了,因为按钮的左偏移值是相对视口的。这就显得左边比上边的偏移距离要小了。

解决方法

之后我学习了关于 CSS 自定义属性(也称为 CSS 变量)方面的知识,我想到可以声明一个变量用来存储滚动条宽度。这样一来,我就可以继续使用 vw 定位元素而无需担心是在 Mac 还是在 Windows 上。

首先需要计算出滚动条宽度。我创建了一个小工具函数,利用 JavaScript 创建的一个临时元素,得到滚动条宽度并返回。

const getScrollbarWidth = () => {
  // Create a temporary div container and append it into the body
  const container = document.createElement('div');
  // Append the container in the body
  document.body.appendChild(container);
  // Force scrollbar on the container
  container.style.overflow = 'scroll';

  // Add ad fake div inside the container
  const inner = document.createElement('div');
  container.appendChild(inner);

  // Calculate the width based on the container width minus its child width
  const width = container.offsetWidth - inner.offsetWidth;
  // Remove the container from the body
  document.body.removeChild(container);

  return width;
};

// Get the scrollbar dimension
const scrollbarWidth = getScrollbarWidth();
// Set a custom property with the value we calculated
document.documentElement.style.setProperty('--scrollbar', `${scrollbarWidth}px`);

在 CSS 中,我创建一个默认变量,以防 Javascript 未启用或触发错误。

:root {
  --scrollbar: 0px;
}

现在我们有了一个包含浏览器滚动条宽度的变量,可以直接在 CSS 中使用它!

.container {
  width: 100vw; /* Fallback for old browsers */
  width: calc(100vw - var(--scrollbar));
}

下面是关闭按钮的样式:

.close {
  position: fixed;
  top: 40px;
  right: 40px; /* Fallback for old browsers */
  right: calc(40px + var(--scrollbar));
}

我希望这篇文章能对你的项目有所帮助!别忘了在 Windows 电脑上测试你的网站哦🤭

(正文完)


广告时间(长期有效)

我有一位好朋友开了一间猫舍,在此帮她宣传一下。现在猫舍里养的都是布偶猫。如果你也是个爱猫人士并且有需要的话,不妨扫一扫她的【闲鱼】二维码。不买也不要紧,看看也行。

(完)