为什么网页在 Windows 上溢出了

最后更新于

不知道你们是否有过这种体验:网页在 Windows 浏览器上(或者插了鼠标的 Mac 上)出现了莫名其妙的内容溢出,即横向或纵向多了一些滚动区域。这通常是因为错误地使用了 vwvh 等 CSS 单位,下面就来看看如何解决这类问题。

如何让元素撑满窗口?

这是继“如何居中DIV”后又一个日经问题。由于根元素本身的 heightauto,其内容元素即使有 height: 100% 也最终会变成按里面的内容计算:

<html style="height: auto">
  <body style="height: 100%"></body>
</html>

html:我的高度按内容计算
body:我的高度要撑满父元素,但父元素没有自己的高度,所以我的高度回退到 auto

所以很简单,只需要把 html body 这条线上的元素都设好 height: 100% 就行。

html,
body {
  height: 100%;
}

为什么我的网页开始出现纵向滚动条了?

如果你在 chrome 系浏览器上试了一下上面的 CSS,会发现出现了纵向“溢出”。怎么会事捏?原来,这是由于 chrome 默认在 body 元素上有一个 margin: 8px,而在两种盒模型里 widthheight 都不含 margin,所以多余的 margin 会使元素变得更大。所以最终 body 的高度实际上是 100% + 8px + 8px。

解决它很简单,我们再把这个碍事的 margin 去掉即可:

html,
body {
  height: 100%;
}
body {
  margin: 0;
}

你说的对,但是 100vh

上面的做法必须得从根元素 html 开始一层层往下铺 height: 100%,有没有一键顶穿屏幕的呢?确实有,可以用 100vw100vh 精确表示完整的屏幕大小。

body {
  margin: 0;
  width: 100vw;
  height: 100vh;
}

“这太简单了”,你想。但事实并非如此,不妨试试往其中加入超出屏幕的内容。

WTF?这时居然同时出现了左右和上下的滚动条。

这是因为,vw 不受滚动条影响,当浏览器决定用滚动条“挤一挤”内容的时候你就输了。而大部分 macOS 开发者在使用触摸板时,系统会显示覆盖渲染的滚动条,它总是不影响内容,所以这是很多 macOS 开发者容易忽视的地方。

手机用户就更悲催了,因为手机浏览器顶部的地址栏会随着滚动收起来,而 vh 的计算不受这个栏影响,结果就是要么内容区少了一截,要么溢出一部分看不见。

所以,在实现撑满元素的时候,尽量别用 vw 等单位,会带来不幸。

其他方式

我不管父元素辣:

body {
  position: absolute;
  inset: 0; /* top/left/right/bottom: 0 的缩写 */
}

position: fixed 也可以,不过可能会导致二级 fixed 的定位计算以及一些 transform 坐标计算出现问题,轻易不要使用。

其他思考

现在的网页越来越从“像报纸”到“像软件”,起手铺满屏幕看似基操,实则可能会失去一些原来像报纸那样的体验。例如,在网页上搜索内容时,chrome 会在滚动条上显示出高亮的线方便定位。但这仅限于原来网页确实有这么高的内容的情况,如果一开始就是 height: 100vh,那这个功能很有可能失效。

GitHub 这方面就做得很好,利用好 position: fixed,也可以在制造出像应用的体验的同时保留原来像报纸一样静态内容的优势。