GSAP ScrollTrigger水平滚动固定时机调整问题求助
解决方案
1. 核心调整思路
- 让最后一个
.gsap-room可以扩展至全屏宽度 - 修正水平滚动的动画目标(从单个房间改为父容器),精准计算滚动结束位置,确保最后一个房间完全显示时,第二个房间仍保留部分可见区域,同时取消
.room-tp的固定状态
2. 修改后的完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>GSAP Horizontal Scroll</title> <style> * { box-sizing: border-box; } body { font-family: "FP-ヒラギノ角ゴ ProN W3", sans-serif; font-style: normal; font-weight: 300; width: 100%; height: 100%; background: #000; color: #fff; font-size: 13px; letter-spacing: 0.05em; line-height: 2.5; word-wrap: break-word; line-break: strict; } #wrapper { position: relative; width: 100%; min-height: 100%; margin: 0; overflow: hidden; } .main { display: block; padding-top: 0; } .block { width: 100%; height: 100vh; background: green; } .room-tp { background: pink; height: 100vh; position: relative; overflow: hidden; width: 100%; } .room-tp .top-title { padding-top: 65px; font-size: 90px; text-align: right; } .room-tp__flex { display: flex; width: max-content; } .room-top__img { width: 80vw; height: calc(100vh - 160px); } .room-top__img img { object-fit: cover; width: 100%; height: 100%; } .room-tp__container { display: block; position: relative; } .big-space { width: 100%; height: 100vh; background-color: red; text-align: center; font-size: 30px; } .blue { background-color: teal; } .gsap-about-flex { display: flex; width: 100%; height: 100vh; background-image: url("https://picsum.photos/200"); background-position: center; background-size: cover; } .gsap-container { position: relative; height: 100vh; } .text-container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; } .text-container h2, .text-container p { color: white; mix-blend-mode: difference; } .gsap-about-before { width: 50%; height: 100vh; background-color: white; } .gsap-about-after { width: 50%; height: 100vh; background-color: white; } /* 新增:让最后一个房间扩展至全屏 */ .gsap-room:last-child { width: 100vw; } .gsap-room:last-child .room-top__img { width: 100%; } </style> </head> <body> <div id="wrapper"> <main class="main"> <div class="block"></div> <div class="gsap-container"> <div class="gsap-about-flex"> <div class="gsap-about-before"></div> <div class="gsap-about-after"></div> </div> <div class="text-container"> <h2>Hello</h2> <p>this is some text</p> </div> </div> <section class="room-tp"> <h2 class="top-title top-title--right">ROOM</h2> <div class="room-tp__wrapper"> <div class="room-tp__flex"> <div class="gsap-room"> <a href="/room/#room401" class="room-tp__container"> <div class="room-top__img"> <img src="https://picsum.photos/id/19/200/300" alt=""> </div> <div class="room-top__info"> <p class="room-top__list">meeting</p> <p class="room-top__info-title">401</p> <a href="/room/#room401" class="room-top__button">VIEW MORE <i class="ico-arrow"></i></a> </div> </a> </div> <div class="gsap-room"> <a href="/room/#room402" class="room-tp__container"> <div class="room-top__img"> <img src="https://picsum.photos/id/20/200/300" alt=""> </div> <div class="room-top__info"> <p class="room-top__list">meeting</p> <p class="room-top__info-title">¥402</p> <a href="/room/#room402" class="room-top__button">VIEW MORE <i class="ico-arrow"></i></a> </div> </a> </div> <div class="gsap-room"> <a href="/room/#room501" class="room-tp__container"> <div class="room-top__img"> <img src="https://picsum.photos/id/21/200/300" alt=""> </div> <div class="room-top__info"> <p class="room-top__list">offline</p> <p class="room-top__info-title">501</p> <a href="/room/#room501" class="room-top__button">VIEW MORE <i class="ico-arrow"></i></a> </div> </a> </div> </div> </div> </section> <div class="block"></div> </main> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/ScrollTrigger.min.js"></script> <script> gsap.registerPlugin(ScrollTrigger); gsap.to(".gsap-about-before", { scrollTrigger: { trigger: ".gsap-container", start: "top top", end: "+=100%", scrub: true, pin: true, toggleActions: "play none none reverse" }, x: '-100%', duration: 3 }); gsap.to(".gsap-about-after", { scrollTrigger: { trigger: ".gsap-container", start: "top top", end: "+=100%", scrub: true, pin: false, toggleActions: "play none none reverse" }, x: '100%', duration: 3 }); // 修改后的水平滚动逻辑 const flexContainer = document.querySelector(".room-tp__flex"); const rooms = gsap.utils.toArray(".gsap-room"); const roomWidth = rooms[0].offsetWidth; // 调整第二个房间的可见宽度,这里设置为20vw(可根据需求修改) const visibleSecondRoomWidth = window.innerWidth * 0.2; // 计算需要滚动的距离:第一个房间宽度 + (第二个房间宽度 - 保留的可见宽度) const scrollDistance = roomWidth + (roomWidth - visibleSecondRoomWidth); gsap.to(flexContainer, { x: -scrollDistance, ease: "none", scrollTrigger: { trigger: ".room-tp", pin: true, scrub: true, end: () => `+=${scrollDistance}`, markers: true, } }); </script> </body> </html>
3. 关键修改说明
- CSS调整:给最后一个
.gsap-room设置width:100vw,让它铺满全屏,同时同步调整内部图片宽度,确保视觉一致性。 - 动画目标修正:将水平滚动动画从单个房间元素改为
.room-tp__flex容器,避免单个元素偏移导致的计算混乱,符合容器级滚动的逻辑。 - 结束条件精准计算:通过
scrollDistance计算滚动总距离,确保最后一个房间完全显示时,第二个房间仍保留20vw的可见区域(可根据需求修改比例),此时触发ScrollTrigger结束状态,取消.room-tp的固定。 - 响应式适配:使用
window.innerWidth * 0.2计算可见宽度,确保在不同屏幕尺寸下效果一致。
内容的提问来源于stack exchange,提问作者Miu_19
相关产品推荐
相关产品推荐

