如何实现类似olaolu.dev的平滑滚动过渡效果(含按钮触发)
实现全屏滚动过渡效果(类似目标站点的页面切换动画)
核心思路
目标站点的效果是全屏区块间的平滑滚动过渡:滚动时当前区块滑出视口,目标区块同步滑入;点击导航按钮时触发完全一致的滚动动画。我们可以通过固定每个页面区块为视口高度,结合CSS过渡动画与JavaScript监听滚动/点击事件来实现。
步骤1:完善HTML结构
补充完整5个页面区块,给所有区块统一类名便于样式控制,同时给导航按钮绑定对应目标区块的ID:
<!doctype html> <html> <head> <link rel="stylesheet" href="/b/cs.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> </head> <body> <!-- 固定侧边导航按钮 --> <div class="btn-container"> <ul> <button class="btn active" data-target="section1"><i class="bi bi-app"></i></button> <button class="btn" data-target="section2"><i class="bi bi-diamond-fill"></i></button> <button class="btn" data-target="section3"><i class="bi bi-diamond-fill"></i></button> <button class="btn" data-target="section4"><i class="bi bi-diamond-fill"></i></button> <button class="btn" data-target="section5"><i class="bi bi-diamond-fill"></i></button> </ul> </div> <!-- 全屏页面区块 --> <section class="full-page active" id="section1"> <div class="details"> <div class="top"> <h2>Faxraddin</h2> <div class="lists"> <button><i class="bi bi-list-check"></i></button> </div> </div> <div class="first-info"> <div class="first-sec"> <h1>Frontend<br> Developer.</h1> <h3 class="profession-info">I like to craft solid and scalable frontend products with great user experiences.</h3> </div> <img class="my-img" src="/b/images/Screenshot 2022-11-04 at 19.35.20.png"> </div> <div class="some-info"> <div class="a1"> <span>Highly skilled at progressive enhancement, design systems & UI Engineering.</span> <span>Over a decade of experience building products for clients across several countries.</span> </div> </div> </div> </section> <section class="full-page" id="section2"> <h2>页面2内容</h2> </section> <section class="full-page" id="section3"> <h2>页面3内容</h2> </section> <section class="full-page" id="section4"> <h2>页面4内容</h2> </section> <section class="full-page" id="section5"> <h2>页面5内容</h2> </section> <script src="/b/js.js"></script> </body> </html>
步骤2:CSS实现布局与过渡动画
在cs.css中设置全屏区块基础样式,添加弹性过渡曲线,定义激活/滑出状态的位置:
* { margin: 0; padding: 0; box-sizing: border-box; } body { overflow: hidden; /* 隐藏全局滚动条,避免干扰区块切换 */ } /* 全屏页面区块 */ .full-page { width: 100vw; height: 100vh; position: absolute; top: 0; left: 0; transition: transform 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); /* 弹性过渡,贴近目标站点效果 */ transform: translateY(100%); /* 默认隐藏在视口下方 */ padding: 2rem; } .full-page.active { transform: translateY(0); /* 激活状态显示在视口内 */ } /* 向下滚动时,上一页滑出到视口上方 */ .full-page.slide-up { transform: translateY(-100%); } /* 向上滚动时,下一页滑出到视口下方 */ .full-page.slide-down { transform: translateY(100%); } /* 侧边导航按钮样式 */ .btn-container { position: fixed; right: 2rem; top: 50%; transform: translateY(-50%); z-index: 100; } .btn-container ul { list-style: none; display: flex; flex-direction: column; gap: 1rem; } .btn { width: 40px; height: 40px; border-radius: 50%; border: none; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.1); cursor: pointer; transition: background 0.3s; } .btn.active { background: #2c3e50; color: #fff; }
步骤3:JavaScript处理交互逻辑
在js.js中实现滚动检测、页面切换动画,以及按钮点击触发逻辑:
const pages = document.querySelectorAll('.full-page'); const btns = document.querySelectorAll('.btn'); let currentPageIndex = 0; let isAnimating = false; // 动画锁:防止未完成时重复触发 // 初始化:激活第一个页面 pages[currentPageIndex].classList.add('active'); // 监听滚轮滚动事件 window.addEventListener('wheel', (e) => { if (isAnimating) return; const direction = e.deltaY > 0 ? 'down' : 'up'; switchPage(direction); }); // 监听导航按钮点击事件 btns.forEach((btn, index) => { btn.addEventListener('click', () => { if (isAnimating || index === currentPageIndex) return; const direction = index > currentPageIndex ? 'down' : 'up'; currentPageIndex = index; animatePageSwitch(direction); updateActiveBtn(); }); }); // 页面切换核心逻辑 function switchPage(direction) { if (direction === 'down' && currentPageIndex < pages.length - 1) { currentPageIndex++; animatePageSwitch(direction); updateActiveBtn(); } else if (direction === 'up' && currentPageIndex > 0) { currentPageIndex--; animatePageSwitch(direction); updateActiveBtn(); } } // 执行页面切换动画 function animatePageSwitch(direction) { isAnimating = true; const prevPage = pages[currentPageIndex - (direction === 'down' ? 1 : -1)]; const currentPage = pages[currentPageIndex]; // 给上一页添加滑出类 prevPage.classList.add(direction === 'down' ? 'slide-up' : 'slide-down'); // 激活当前页 currentPage.classList.add('active'); // 动画结束后清理类名,释放动画锁 setTimeout(() => { prevPage.classList.remove('active', 'slide-up', 'slide-down'); isAnimating = false; }, 600); // 时间与CSS过渡时间保持一致 } // 更新导航按钮激活状态 function updateActiveBtn() { btns.forEach(btn => btn.classList.remove('active')); btns[currentPageIndex].classList.add('active'); }
关键说明
- 动画曲线:使用
cubic-bezier(0.68, -0.55, 0.265, 1.55)实现类似目标站点的弹性滑入效果,可根据需求调整参数。 - 动画锁:通过
isAnimating变量避免滚动/点击在动画未完成时重复触发,防止页面状态混乱。 - 响应式适配:移动端可调整
full-page的内边距和按钮尺寸,保证触控操作的便捷性。
内容的提问来源于stack exchange,提问作者Count of Monte Cristo
相关产品推荐
相关产品推荐

