如何实现仅在div进入视口时触发Vanilla JS平滑视差效果?
视差滚动脚本优化需求
我参照Design Course的原生JS视差教程实现了基础的垂直/水平视差效果,未使用lax.js等第三方库。但将该脚本应用到视口下方的div时,出现两个问题:
- 元素初始transform值被脚本篡改
- 元素进入视口前就已触发滚动效果,且距离视口越远问题越严重
我尝试过用getBoundingClientRect()结合window.scrollY + window.innerHeight实现「仅在元素进入视口后触发视差」,但未成功。
更新:我已在JS中加入Intersection Observer,现在可实现视口内触发视差(配置了rootMargin),但元素移动仍不流畅,原因是translate值被提前设置。
当前代码中蓝色、绿色盒子效果正常,但红色、黄色盒子表现不佳。希望修改JS逻辑,让下方div的视差效果仅在其顶部边缘到达自定义触发坐标后才生效——触发位置可通过HTML的data-trigger属性定义,例如设置为window.scrollY + window.innerHeight或(window.scrollY + window.innerHeight) - dataset.trigger这类计算值。
现有代码
HTML
<section id="top-section"> <div id="blue-box" class="boxes parallax" data-rate="0.25" data-direction="vertical" ></div> <div id="green-box" class="boxes parallax" data-ratex="0.25" data-ratey="1" data-direction="horizontal" ></div> </section> <section id="middle-section"> <div id="red-box" class="boxes parallax" data-rate="0.5" data-direction="vertical" ></div> </section> <section id="bottom-section"> <div id="yellow-box" class="boxes parallax" data-rate="1" data-direction="vertical" ></div> </section>
CSS
section { display: flex; justify-content: center; align-items: center; height: 100vh; } #top-section { background: black; } #middle-section { background: white; } #bottom-section { background: blue; } .boxes { width: 100px; height: 100px; } #blue-box { background: blue; } #green-box { background: green; } #red-box { background: red; } #yellow-box { background: yellow; }
JavaScript
const parallaxEls = document.querySelectorAll('.parallax'); const parallaxObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { entry.target.classList.toggle('paractive', entry.isIntersecting); }); }, { rootMargin: '-250px', } ); parallaxEls.forEach((parallaxEl) => { parallaxObserver.observe(parallaxEl); }); window.addEventListener('scroll', function (e) { const parallaxed = document.querySelectorAll('.paractive'); let index = 0, length = parallaxed.length; for (index; index < length; index++) { const pos = window.scrollY * parallaxed[index].dataset.rate; if (parallaxed[index].dataset.direction === 'vertical') { parallaxed[index].style.transform = 'translate3d(0, ' + pos + 'px, 0)'; } else { const posX = window.scrollY * parallaxed[index].dataset.ratex; const posY = window.scrollY * parallaxed[index].dataset.ratey; parallaxed[index].style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, 0)'; } } });
内容的提问来源于stack exchange,提问作者Robith Nuriel Haq
相关产品推荐
相关产品推荐

