圖片輪播、全屏滾動頁面、橫向滾動卡片——這些常見的交互效果過去往往需要依賴 JavaScript 庫實現。CSS Scroll Snap 屬性讓我們可以用純 CSS 實現滾動吸附效果,性能更好、代碼更簡潔。2019 年,Scroll Snap 已經獲得了主流瀏覽器的廣泛支持。本文將系統講解 Scroll Snap 的用法和實戰案例。
核心概念
Scroll Snap 涉及兩個關鍵屬性:
scroll-snap-type— 設置在滾動容器上,定義滾動軸和吸附嚴格程度scroll-snap-align— 設置在子元素上,定義吸附位置
基礎用法:水平輪播
html
<div class="carousel">
<div class="slide slide-1">Slide 1</div>
<div class="slide slide-2">Slide 2</div>
<div class="slide slide-3">Slide 3</div>
<div class="slide slide-4">Slide 4</div>
</div>
css
.carousel {
display: flex;
overflow-x: auto;
/* 設置滾動吸附 */
scroll-snap-type: x mandatory;
/* 隱藏滾動條(可選) */
-webkit-overflow-scrolling: touch;
/* 平滑滾動 */
scroll-behavior: smooth;
}
/* 隱藏滾動條但保留滾動功能 */
.carousel::-webkit-scrollbar {
display: none;
}
.slide {
/* 每個 slide 佔滿一屏 */
min-width: 100vw;
height: 100vh;
/* 設置吸附位置 */
scroll-snap-align: start;
/* 居中內容 */
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
}
.slide-1 { background: #ff6b6b; color: white; }
.slide-2 { background: #4ecdc4; color: white; }
.slide-3 { background: #45b7d1; color: white; }
.slide-4 { background: #96ceb4; color: white; }
scroll-snap-type 詳解
css
/* 語法 */
scroll-snap-type: <axis> <strictness>;
/* axis: x | y | block | inline | both */
scroll-snap-type: x; /* 水平方向 */
scroll-snap-type: y; /* 垂直方向 */
scroll-snap-type: both; /* 兩個方向 */
scroll-snap-type: block; /* 文本流方向(與 writing-mode 相關) */
scroll-snap-type: inline; /* 行內方向 */
/* strictness: none | proximity | mandatory */
scroll-snap-type: x mandatory; /* 嚴格吸附,必須對齊到吸附點 */
scroll-snap-type: x proximity; /* 寬鬆吸附,儘量對齊但不強制 */
mandatory— 滾動停止時必須對齊到吸附點。適用於輪播圖、全屏滾動等精確場景proximity— 滾動停止時儘量對齊,但位置不夠精確時不會強制調整。適用於長列表等自然滾動場景
scroll-snap-align 詳解
css
/* 語法 */
scroll-snap-align: <alignment>;
/* alignment: none | start | center | end | <value> <value> */
scroll-snap-align: start; /* 子元素起始邊對齊容器起始邊 */
scroll-snap-align: center; /* 子元素中心對齊容器中心 */
scroll-snap-align: end; /* 子元素結束邊對齊容器結束邊 */
scroll-snap-align: start end; /* 第一個值:行內方向,第二個值:塊方向 */
全屏滾動頁面
html
<div class="fullpage-scroll">
<section class="section" id="home">首頁</section>
<section class="section" id="about">關於</section>
<section class="section" id="work">作品</section>
<section class="section" id="contact">聯繫</section>
</div>
css
.fullpage-scroll {
height: 100vh;
overflow-y: auto;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
}
.section {
height: 100vh;
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
}
#home { background: linear-gradient(135deg, #667eea, #764ba2); color: white; }
#about { background: linear-gradient(135deg, #f093fb, #f5576c); color: white; }
#work { background: linear-gradient(135deg, #4facfe, #00f2fe); color: white; }
#contact { background: linear-gradient(135deg, #43e97b, #38f9d7); color: white; }
卡片列表吸附
適用於產品展示、文章列表等場景:
html
<div class="card-container">
<div class="card">Card 1</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
<div class="card">Card 5</div>
</div>
css
.card-container {
display: flex;
gap: 16px;
overflow-x: auto;
padding: 20px;
scroll-snap-type: x proximity; /* 寬鬆吸附 */
/* 讓邊緣的卡片也能居中顯示 */
scroll-padding: 0 calc(50% - 150px);
}
.card {
min-width: 300px;
height: 200px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
scroll-snap-align: center;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
transition: transform 0.3s;
}
.card:hover {
transform: scale(1.02);
}
scroll-snap-stop 控制滾動穿透
默認情況下,快速滑動可能跳過多個吸附點。scroll-snap-stop 可以控制這個行為:
css
.slide {
scroll-snap-align: start;
/* normal: 允許跳過 | always: 每次必須停留 */
scroll-snap-stop: always;
}
這個屬性特別適合需要用户逐頁閲讀的場景,如新手引導頁。
scroll-padding 和 scroll-margin
scroll-padding(設置在容器上)
在滾動容器內設置內邊距,不影響佈局但影響吸附位置:
css
/* 有固定導航欄時,避免內容被遮擋 */
.fullpage-scroll {
scroll-snap-type: y mandatory;
scroll-padding-top: 60px; /* 導航欄高度 */
}
.section {
scroll-snap-align: start;
}
scroll-margin(設置在子元素上)
為單個子元素設置外邊距:
css
.section {
scroll-snap-align: start;
scroll-margin-top: 60px; /* 僅這個 section 有頂部偏移 */
}
實戰:圖片畫廊
html
<div class="gallery">
<div class="gallery-item">
<img src="photo1.jpg" alt="照片1">
</div>
<div class="gallery-item">
<img src="photo2.jpg" alt="照片2">
</div>
<div class="gallery-item">
<img src="photo3.jpg" alt="照片3">
</div>
</div>
css
.gallery {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
gap: 10px;
padding: 10px;
scroll-padding: 10px;
}
.gallery-item {
scroll-snap-align: center;
scroll-snap-stop: always;
flex: 0 0 auto;
border-radius: 8px;
overflow: hidden;
}
.gallery-item img {
height: 300px;
width: auto;
object-fit: cover;
display: block;
}
垂直內容導航
配合側邊導航使用,實現點擊導航自動滾動:
html
<div class="layout">
<nav class="side-nav">
<a href="#section1">第一節</a>
<a href="#section2">第二節</a>
<a href="#section3">第三節</a>
</nav>
<main class="content">
<section id="section1">內容一</section>
<section id="section2">內容二</section>
<section id="section3">內容三</section>
</main>
</div>
css
.content {
height: 100vh;
overflow-y: auto;
scroll-snap-type: y proximity;
scroll-behavior: smooth;
}
section {
min-height: 100vh;
scroll-snap-align: start;
padding: 40px;
border-bottom: 1px solid #eee;
}
瀏覽器兼容性
2019 年 8 月的支持情況:
- Chrome 69+ — 完整支持
- Firefox 68+ — 完整支持
- Safari 11+ — 完整支持(需要
-webkit-前綴) - Edge 79+ — 完整支持
- IE — 不支持
對於不支持的瀏覽器,可以添加漸進增強:
css
@supports (scroll-snap-type: x mandatory) {
.carousel {
scroll-snap-type: x mandatory;
}
.slide {
scroll-snap-align: start;
}
}
/* 不支持的瀏覽器仍然可以正常使用滾動,只是沒有吸附效果 */
小結
scroll-snap-type設置在容器上定義滾動軸和吸附嚴格度,scroll-snap-align設置在子元素上定義吸附位置mandatory嚴格吸附適用於輪播圖等精確場景,proximity寬鬆吸附適用於列表等自然滾動場景scroll-snap-stop: always可以防止快速滑動時跳過內容scroll-padding和scroll-margin用於處理固定導航欄等偏移場景- 使用
@supports做漸進增強,不支持的瀏覽器仍可正常使用滾動功能 - 純 CSS 實現,性能優於 JavaScript 方案,推薦在新項目中優先使用