Skip to content

滚动与溢出

当内容超出容器边界时,CSS 提供了丰富的属性来控制溢出行为。现代 CSS 还带来了滚动捕捉、平滑滚动、自定义滚动条等特性,让滚动体验更加精致。

溢出处理#

overflow#

控制内容溢出时的显示方式:

.visible {
overflow: visible;
} /* 默认:内容可见,超出容器 */
.hidden {
overflow: hidden;
} /* 裁剪溢出内容 */
.scroll {
overflow: scroll;
} /* 始终显示滚动条 */
.auto {
overflow: auto;
} /* 需要时显示滚动条 */
.clip {
overflow: clip;
} /* 裁剪,不可滚动 */

分轴控制#

.horizontal-scroll {
overflow-x: auto;
overflow-y: hidden;
}
.vertical-scroll {
overflow-x: hidden;
overflow-y: auto;
}

overflow: clip vs hidden#

.hidden {
overflow: hidden;
/* 仍可通过 JS 滚动 */
}
.clip {
overflow: clip;
/* 完全禁止滚动,性能更好 */
}
/* clip 可以配合 overflow-clip-margin */
.clip-with-margin {
overflow: clip;
overflow-clip-margin: 20px; /* 允许溢出 20px */
}

滚动行为#

scroll-behavior#

平滑滚动:

html {
scroll-behavior: smooth;
}
/* 或针对特定容器 */
.scroll-container {
scroll-behavior: smooth;
}

🎯 配合锚点链接使用效果最佳:

<a href="#section">跳转到章节</a>
<section id="section">目标位置</section>

overscroll-behavior#

控制滚动到边界时的行为:

.modal {
overscroll-behavior: contain;
} /* 阻止滚动链传递 */
.no-bounce {
overscroll-behavior: none;
} /* 禁用弹性效果 */
.default {
overscroll-behavior: auto;
} /* 默认行为 */

🎯 contain 是弹窗的最佳选择,防止滚动穿透到背景。

/* 分轴控制 */
.horizontal-only {
overscroll-behavior-x: contain;
overscroll-behavior-y: auto;
}

滚动捕捉#

scroll-snap-type#

创建类似轮播的滚动效果:

.snap-container {
scroll-snap-type: x mandatory;
overflow-x: auto;
}
/* 轴向 */
.snap-x {
scroll-snap-type: x mandatory;
}
.snap-y {
scroll-snap-type: y mandatory;
}
.snap-both {
scroll-snap-type: both mandatory;
}
/* 严格程度 */
.mandatory {
scroll-snap-type: x mandatory;
} /* 必须停在捕捉点 */
.proximity {
scroll-snap-type: x proximity;
} /* 接近时才捕捉 */

scroll-snap-align#

子元素的对齐方式:

.snap-item {
scroll-snap-align: start;
} /* 对齐到起始边 */
.snap-center {
scroll-snap-align: center;
} /* 居中对齐 */
.snap-end {
scroll-snap-align: end;
} /* 对齐到结束边 */

scroll-snap-stop#

强制停止:

.must-stop {
scroll-snap-stop: always;
} /* 必须在此停止 */
.normal {
scroll-snap-stop: normal;
} /* 可能跳过 */

scroll-padding / scroll-margin#

调整捕捉位置:

/* 容器的内边距(考虑固定头部) */
.snap-container {
scroll-padding-top: 80px;
}
/* 子元素的外边距 */
.snap-item {
scroll-margin: 20px;
}

完整轮播示例#

.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding: 20px;
gap: 20px;
padding: 20px;
/* 隐藏滚动条 */
scrollbar-width: none;
-ms-overflow-style: none;
}
.carousel::-webkit-scrollbar {
display: none;
}
.carousel-item {
flex: 0 0 300px;
scroll-snap-align: center;
scroll-snap-stop: always;
border-radius: 12px;
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

自定义滚动条#

标准属性(Firefox)#

.custom-scrollbar {
scrollbar-width: thin; /* auto | thin | none */
scrollbar-color: #3b82f6 #f1f5f9; /* 滑块颜色 轨道颜色 */
}

WebKit 属性(Chrome/Safari/Edge)#

/* 整体样式 */
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/* 轨道 */
.custom-scrollbar::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 4px;
}
/* 滑块 */
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #94a3b8;
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #64748b;
}
/* 角落 */
.custom-scrollbar::-webkit-scrollbar-corner {
background: #f1f5f9;
}

隐藏滚动条#

.hide-scrollbar {
overflow: auto;
/* Firefox */
scrollbar-width: none;
/* IE/Edge */
-ms-overflow-style: none;
}
/* Chrome/Safari */
.hide-scrollbar::-webkit-scrollbar {
display: none;
}

滚动驱动动画#

scroll()#

基于滚动位置的动画(Chrome 115+):

@keyframes fade-in {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.scroll-animate {
animation: fade-in linear;
animation-timeline: scroll();
animation-range: entry 0% cover 40%;
}

view()#

基于元素可见性的动画:

.reveal {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}

🔶 滚动驱动动画是较新的特性,请检查浏览器兼容性。

实战案例#

固定头部滚动#

.page {
scroll-padding-top: 80px; /* 头部高度 */
}
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
z-index: 100;
}
/* 平滑滚动到锚点 */
html {
scroll-behavior: smooth;
}

弹窗防滚动穿透#

.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
overflow-y: auto;
overscroll-behavior: contain;
}
.modal {
max-height: 80vh;
overflow-y: auto;
overscroll-behavior: contain;
}
/* 打开弹窗时锁定 body */
body.modal-open {
overflow: hidden;
}

全屏滚动页面#

.fullpage {
height: 100vh;
overflow-y: auto;
scroll-snap-type: y mandatory;
}
.fullpage-section {
height: 100vh;
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
}

横向图片画廊#

.gallery {
display: flex;
gap: 16px;
padding: 16px;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding: 16px;
/* 美化滚动条 */
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}
.gallery::-webkit-scrollbar {
height: 6px;
}
.gallery::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.2);
border-radius: 3px;
}
.gallery-item {
flex: 0 0 auto;
width: 280px;
aspect-ratio: 3 / 4;
scroll-snap-align: center;
border-radius: 12px;
overflow: hidden;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
}

卡片列表虚拟滚动提示#

.scroll-hint {
position: relative;
overflow: hidden;
}
.scroll-hint::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60px;
background: linear-gradient(transparent, white);
pointer-events: none;
}
/* 滚动到底部时隐藏 */
.scroll-hint.scrolled-to-bottom::after {
opacity: 0;
}

聊天窗口自动滚动#

.chat-messages {
display: flex;
flex-direction: column;
height: 400px;
overflow-y: auto;
overscroll-behavior: contain;
/* 从底部开始 */
flex-direction: column-reverse;
}
/* 或使用 JS 配合 scroll-snap */
.chat-messages-snap {
overflow-y: auto;
scroll-snap-type: y proximity;
}
.chat-messages-snap > *:last-child {
scroll-snap-align: end;
}

回到顶部按钮#

html {
scroll-behavior: smooth;
}
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
width: 48px;
height: 48px;
border-radius: 50%;
background: #3b82f6;
color: white;
border: none;
cursor: pointer;
opacity: 0;
transform: translateY(20px);
transition:
opacity 0.3s,
transform 0.3s;
}
.back-to-top.visible {
opacity: 1;
transform: translateY(0);
}

性能优化#

contain 属性#

限制布局计算范围:

.scroll-item {
contain: layout style paint;
}
/* 或简写 */
.scroll-item {
contain: content;
}

content-visibility#

延迟渲染屏幕外内容:

.long-list-item {
content-visibility: auto;
contain-intrinsic-size: auto 200px; /* 预估高度 */
}

will-change#

提示浏览器优化:

.scroll-container {
will-change: scroll-position;
}
/* 用完记得移除 */
.optimized-element {
will-change: transform;
}

常见问题#

🤔 滚动条占用布局空间怎么办?

.container {
scrollbar-gutter: stable; /* 预留滚动条空间 */
}

🤔 iOS Safari 弹性滚动问题?

.container {
-webkit-overflow-scrolling: touch; /* 启用惯性滚动 */
overscroll-behavior: contain; /* 防止传递 */
}

🤔 如何检测滚动位置?

使用 JavaScript 的 IntersectionObserverscroll 事件,结合 CSS 类切换实现效果。


CSS 滚动和溢出处理是构建流畅用户体验的关键。从基础的 overflow 到现代的滚动捕捉、滚动驱动动画,掌握这些技术能让你的页面滚动体验更加精致。下一篇我们将学习裁剪与遮罩。