方案 1:纯 CSS Scroll Snap
原理:利用 CSS 的 scroll-snap 属性实现无 JS 吸附滚动
优点:零依赖、性能最佳、代码简洁
问题:鼠标连续滚动时体验不佳,scroll-snap的机制是在滚动操作结束后才会触发吸附,快速连续滚动时,由于滚动并未真正"结束",可能导致吸附行为不能及时生效
<!DOCTYPE html>
<style>
html, body { margin: 0; height: 100%; }
.scroll-container {
height: 100vh;
overflow-y: scroll;
scroll-snap-type: y mandatory; /* 关键属性 */
}
.page {
height: 100vh;
scroll-snap-align: start; /* 吸附点 */
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
}
.page:nth-child(1) { background: #FF6B6B; }
.page:nth-child(2) { background: #4ECDC4; }
.page:nth-child(3) { background: #45B7D1; }
</style>
<div class="scroll-container">
<section class="page">Page 1</section>
<section class="page">Page 2</section>
<section class="page">Page 3</section>
</div>方案 2:使用现成库(快速开发)
推荐库:
fullPage.js(功能最全)
Swiper(移动端友好)(把每一页当成一个幻灯片)
Scrollify(轻量级)
示例(fullPage.js):
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.15/fullpage.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.15/fullpage.min.js"></script>
<div id="fullpage">
<div class="section">第一屏</div>
<div class="section">第二屏</div>
<div class="section">第三屏</div>
</div>
<script>
new fullpage('#fullpage', {
licenseKey: 'OPEN-SOURCE-GPLV3-LICENSE'
});
</script>方案 3:JavaScript + CSS 动画
原理:监听滚动事件,用 transform 动画移动页面
优点:兼容性更好,可控制动画曲线
缺点:需要手动处理滚动逻辑
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; overflow: hidden; }
.page {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
color: white;
}
#container {
transition: transform 0.8s cubic-bezier(0.22, 1, 0.36, 1); /* 弹性动画 */
}
.page:nth-child(1) { background: #FF6B6B; }
.page:nth-child(2) { background: #4ECDC4; }
.page:nth-child(3) { background: #45B7D1; }
</style>
</head>
<body>
<div id="container">
<div class="page">第一屏</div>
<div class="page">第二屏</div>
<div class="page">第三屏</div>
</div>
<script>
let current = 0;
let isAnimating = false; // 动画锁定标志
const container = document.getElementById("container");
const pageCount = document.querySelectorAll('.page').length;
function goToPage(newPage) {
if (isAnimating) return;
if (newPage < 0 || newPage >= pageCount) return;
isAnimating = true;
current = newPage;
container.style.transform = `translateY(-${current * 100}vh)`;
// 动画结束后解锁
setTimeout(() => isAnimating = false, 800);
}
window.addEventListener('wheel', (e) => {
e.preventDefault(); // 阻止默认滚动
if (e.deltaY > 0) goToPage(current + 1); // 向下滚动
if (e.deltaY < 0) goToPage(current - 1); // 向上滚动
}, { passive: false });
</script>
</body>
</html>