CSS Handbook · 布局

第六章 / 6.2 overflow 与滚动容器

第六章 · 6.2 节

overflow 与滚动容器


当子内容尺寸超出容器时该怎么办,是布局中绕不开的问题。overflow 决定了"溢出的部分是显示、裁剪,还是变成可滚动区域",同时它还会悄悄触发一个重要的副作用——创建新的块格式化上下文(BFC)。

overflow 的取值

取值效果
visible(默认)溢出内容照常显示,不裁剪、不产生滚动条
hidden溢出内容被裁剪且不可见,也无法通过滚动查看
scroll始终显示滚动条(即使内容未溢出),裁剪溢出内容
auto仅在内容溢出时才显示滚动条,最常用的取值
clip类似 hidden,但禁止编程式滚动(如 scrollTo),性能更好
overflow: auto 效果
这是一段足够长的文字,用来撑爆容器的高度,从而演示 overflow: auto 在内容溢出时才出现滚动条的行为——继续往下滚动就能看到全部内容。这里再补一句凑够长度。

分轴控制

overflow 是 overflow-x 与 overflow-y 的简写,可以分别控制两个方向:

.gallery {
  overflow-x: auto;  /* 横向可滚动,常用于图片走廊 */
  overflow-y: hidden; /* 垂直方向裁剪,不产生纵向滚动条 */
  white-space: nowrap;
}
注意两个方向只要有一个不是 visible,另一个即使设置为 visible 也会被自动计算为 auto——浏览器不允许"一个方向裁剪、另一个方向内容还能随意溢出跑到裁剪区域外"。

overflow 与 BFC

给容器设置除 visible/clip 之外的 overflow 值,会让它成为一个新的块格式化上下文(Block Formatting Context)。这是早期最常用的"清除浮动"手法之一——父元素触发 BFC 后,会正确包裹住内部的浮动子元素高度。完整的 BFC 触发条件与浮动布局见 6.5 浮动与 BFC。

.clearfix-legacy {
  overflow: hidden; /* 触发 BFC,父元素高度重新包住浮动子元素 */
}

overscroll-behavior

控制滚动到容器边界后,是否将滚动"传导"给父级或整个页面——典型场景是防止弹层内部滚动到底部后,继续下滑触发背后页面的滚动(俗称"滚动穿透")。

.modal-body {
  overflow-y: auto;
  overscroll-behavior: contain; /* 滚动到边界后不再传导给页面 */
}

scrollbar-gutter 与滚动条布局抖动

内容变化导致 overflow: auto 的容器在"有滚动条"和"无滚动条"之间切换时,非覆盖式滚动条(如 Windows 默认样式)会占用布局空间,造成内容左右抖动。scrollbar-gutter 可以提前预留这部分空间:

.list {
  overflow-y: auto;
  scrollbar-gutter: stable; /* 无论是否出现滚动条,都预留其宽度 */
}

层叠上下文速查

z-index 与层叠上下文的完整讲解见 6.1 盒模型与定位,这里补充一份速查表,列出会创建新层叠上下文的常见触发条件:

  • position 为 relative/absolute/sticky/fixed 且显式设置了 z-index(非 auto)。
  • opacity 小于 1。
  • transform、filter、perspective 取值不为 none。
  • will-change 指定了以上任一属性。
  • flex/grid 容器的子项,且 z-index 不为 auto。
  • isolation: isolate——不改变任何视觉效果,唯一作用就是显式创建一个新的层叠上下文,常用于隔离某个组件内部的 z-index,避免影响页面其他区域。

常见误区

  • 给弹窗/抽屉设置 overflow: hidden 想裁剪内容,却意外裁掉了子元素的 box-shadow 或 tooltip——这类"溢出但需要可见"的视觉效果,应考虑用额外的包裹层隔离 overflow。
  • 忘记 overflow: hidden 会创建 BFC,导致容器内原本设计为"溢出可见"的子元素被意外裁剪。
  • 用很大的 z-index(如 9999)暴力解决层级问题,而没有意识到真正的原因是某个祖先创建了限制性的层叠上下文。

Chapter 6 · Section 6.2

overflow and Scrolling Containers


What to do when child content exceeds the container is an unavoidable question in layout. overflow decides whether overflowing content is shown, clipped, or turned into a scrollable region — and it quietly triggers an important side effect: creating a new block formatting context (BFC).

The Values of overflow

ValueEffect
visible (default)Overflowing content is shown as usual; nothing is clipped and no scrollbar appears
hiddenOverflowing content is clipped and invisible, and cannot be reached by scrolling
scrollAlways shows a scrollbar (even when content does not overflow), and clips overflowing content
autoShows a scrollbar only when content overflows; the most commonly used value
clipLike hidden, but forbids programmatic scrolling (e.g. scrollTo) and performs better
overflow: auto in action
This is a long enough piece of text to overflow the container's height, demonstrating how overflow: auto only shows a scrollbar when content overflows — keep scrolling down to see all of it. One more sentence to make it long enough.

Controlling Each Axis

overflow is the shorthand for overflow-x and overflow-y, letting you control the two directions separately:

.gallery {
  overflow-x: auto;  /* horizontally scrollable, often used for image galleries */
  overflow-y: hidden; /* clips vertically, no vertical scrollbar */
  white-space: nowrap;
}
NoteAs long as one direction is not visible, the other is automatically computed as auto even if you set it to visible — browsers do not allow "one direction clipped while content can still overflow freely past the clip in the other".

overflow and BFC

Giving a container any overflow value other than visible/clip makes it a new block formatting context (Block Formatting Context). This was one of the earliest, most common "clear floats" techniques — once the parent triggers a BFC, it correctly wraps the height of the floated children inside it. For the full list of BFC triggers and float layout, see 6.5 Floats and BFC.

.clearfix-legacy {
  overflow: hidden; /* triggers a BFC so the parent's height wraps the floated children again */
}

overscroll-behavior

Controls whether scrolling is "propagated" to the parent or the whole page once the container's edge is reached — the typical case is preventing a popup's inner scroll from triggering the page behind it after reaching the bottom (commonly called "scroll chaining").

.modal-body {
  overflow-y: auto;
  overscroll-behavior: contain; /* once the edge is reached, scrolling is no longer propagated to the page */
}

scrollbar-gutter and Scrollbar Layout Shifting

When content changes make an overflow: auto container flip between "with scrollbar" and "without scrollbar", non-overlay scrollbars (such as the Windows default) occupy layout space and make the content jitter sideways. scrollbar-gutter can reserve that space in advance:

.list {
  overflow-y: auto;
  scrollbar-gutter: stable; /* always reserves its width whether or not a scrollbar appears */
}

Stacking Context Cheat Sheet

For the full explanation of z-index and stacking contexts, see 6.1 The Box Model and Positioning. Here is a quick-reference list of common triggers that create a new stacking context:

  • position is relative/absolute/sticky/fixed with an explicit z-index (not auto).
  • opacity is less than 1.
  • transform, filter, or perspective is set to something other than none.
  • will-change specifies any of the properties above.
  • A child of a flex/grid container whose z-index is not auto.
  • isolation: isolate — changes no visual effect; its only job is to explicitly create a new stacking context, often used to isolate a component's internal z-index so it cannot affect the rest of the page.

Common Pitfalls

  • Setting overflow: hidden on a popup/drawer to clip content, but accidentally clipping a child's box-shadow or tooltip — for visual effects that "overflow but must stay visible", consider isolating overflow with an extra wrapper layer.
  • Forgetting that overflow: hidden creates a BFC, so children that were designed to "overflow visibly" get clipped unexpectedly.
  • Brute-forcing a layering problem with a huge z-index (e.g. 9999) without realizing the real cause is an ancestor that created a restrictive stacking context.