背景介绍
在当今的网页设计中,流畅的交互体验已成为用户评价产品品质的重要标准之一。其中,滚动吸附(Scroll Snapping) 作为一种常见的交互模式,通过将滚动内容自动对齐到预设的"吸附点"(如视口的顶部、底部或页面边界),为用户提供了一种精准、顺滑的浏览体验。这种技术被广泛应用于全屏轮播图、垂直/横向分页导航、长表单分步填写等场景,尤其在移动端触屏设备中,手指滑动后内容自动"吸附"到完整屏幕的特性,显著降低了用户的操作成本。
方法一:纯 CSS 实现
- 使用
scroll-snap-type: y mandatory
启用垂直滚动吸附 - 每个 section 设置
scroll-snap-align: start
对齐顶部 - 隐藏滚动条提升美观度(可选)
xml
<!DOCTYPE html>
<meta charset="UTF-8">
<head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
height: 100vh;
overflow-y: scroll;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
}
section {
height: 100vh;
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4em;
}
/* 可选:隐藏滚动条 */
.container::-webkit-scrollbar {
display: none;
}
</style>
</head>
<body>
<div class="container">
<section style="background: #ff6b6b;">第一屏</section>
<section style="background: #4ecdc4;">第二屏</section>
<section style="background: #45b7d1;">第三屏</section>
<section style="background: #96ceb4;">第四屏</section>
</div>
</body>
</html>
方法二:JavaScript 增强控制
- 监听鼠标滚轮事件
- 判断滚动方向(上/下)
- 使用
scrollIntoView()
实现平滑滚动 - 通过 flag 防止滚动冲突
xml
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
height: 100vh;
overflow-y: scroll;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch; /* 移动端滚动优化 */
}
section {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 4em;
scroll-snap-align: start; /* 辅助平滑定位 */
}
</style>
</head>
<body>
<div class="container">
<section style="background: #ff6b6b;">第一屏</section>
<section style="background: #4ecdc4;">第二屏</section>
<section style="background: #45b7d1;">第三屏</section>
<section style="background: #96ceb4;">第四屏</section>
</div>
<script>
let current = 0;
let startY = 0;
const sections = document.querySelectorAll('section');
const container = document.querySelector('.container');
let isScrolling = false;
const threshold = 50; // 滑动阈值
// 桌面端滚轮事件
container.addEventListener('wheel', handleWheel, { passive: false });
// 移动端触摸事件
container.addEventListener('touchstart', handleTouchStart, { passive: false });
container.addEventListener('touchend', handleTouchEnd, { passive: false });
// 滚动事件
function handleWheel(e) {
e.preventDefault();
if (isScrolling) return;
const delta = Math.sign(e.deltaY);
navigate(delta);
}
// 点击开始,如果是PC可以不要
function handleTouchStart(e) {
startY = e.touches[0].clientY;
}
// 点击结束,如果是PC可以不要
function handleTouchEnd(e) {
if (isScrolling) return;
const endY = e.changedTouches[0].clientY;
const delta = startY - endY; // 滑动距离
if (Math.abs(delta) > threshold) {
navigate(delta > 0 ? 1 : -1);
}
}
// 计算滚动的最终位置
function navigate(direction) {
const newIndex = current + direction;
if (newIndex >= 0 && newIndex < sections.length) {
current = newIndex;
scrollToSection();
}
}
// 滑动
function scrollToSection() {
isScrolling = true;
sections[current].scrollIntoView({
behavior: 'smooth',
block: 'start'
});
setTimeout(() => {
isScrolling = false;
}, 800);
}
// 禁用移动端双指缩放,如果是PC可以不要
document.addEventListener('gesturestart', (e) => e.preventDefault());
document.addEventListener('gesturechange', (e) => e.preventDefault());
</script>
</body>
</html>
总结
- 推荐优先使用 CSS 方案,性能更好且代码更简洁
- 可以通过修改
scroll-behavior
或动画时间调整滚动速度 - 确保内容区块高度严格等于视口高度(100vh)