英文:
GSAP ScrollTrigger runs on all animations at the same time, even for elements not in the viewport
问题
I have several content blocks stacked on a page that will all share the same animation on scroll.
我有几个在页面上堆叠的内容块,它们都会在滚动时共享相同的动画。
Currently, the animation runs on all the blocks at the same time, when the first item with the relevant class/trigger enters the viewport.
目前,当具有相关类/触发器的第一个项目进入视口时,动画会同时在所有块上运行。
How do I make sure the animation only runs on the relevant element that is entering/leaving the viewport?
如何确保动画仅在进入/离开视口的相关元素上运行?
As an aside I'd like the animation to run the length of the viewport, so the animation starts when the top edge of the image enters the viewport and ends as the bottom edge leaves...not sure if it's doing that at the moment.
此外,我希望动画在整个视口的长度上运行,因此动画在图像的顶部边缘进入视口时开始,并在底部边缘离开时结束...不确定目前是否已实现。
I tried putting the script into an array based on this article but it doesn't seem to work with my timeline.
我尝试将脚本放入一个数组中基于这篇文章,但似乎与我的时间轴不兼容。
const stories = gsap.utils.toArray('.story__media');
stories.forEach(story => {
var tl = gsap.timeline(story, {
scrollTrigger: {
trigger: ".story__media",
scrub: true,
start: "top top",
end: "bottom bottom"
}
});
tl.from(".story__media img", {scale: 2, ease: "power2"})
});
```javascript
gsap.registerPlugin(ScrollTrigger);
var tl = gsap.timeline({
scrollTrigger: {
trigger: ".story__media",
scrub: true,
start: "-100%",
end: "+=200%"
}
});
tl.from(".story__media img", {
scale: 1.4,
ease: "power2"
})
img {
display: block;
width: 100%;
max-width: 100%;
}
.story {
display: grid;
grid-template-columns: repeat(12, 1fr);
column-gap: 4px;
padding: 64px 0;
}
.story__media {
grid-column: 2 / span 5;
overflow: hidden;
}
.story__caption-wrap {
grid-column: 8 / span 4;
}
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js?v=3.3.0-3"></script>
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
英文:
I have several content blocks stacked on a page that will all share the same animation on scroll.
Currently, the animation runs on all the blocks at the same time, when the first item with the relevant class/trigger enters the viewport.
How do I make sure the animation only runs on the relevant element that is entering/leaving the viewport?
As an aside I'd like the animation to run the length of the viewport, so the animation starts when the top edge of the image enters the viewport and ends as the bottom edge leaves ...not sure if it's doing that at the moment.
I tried putting the script into an array based on this article but it doesn't seem to work with my timeline.
const stories = gsap.utils.toArray('.story__media');
stories.forEach(story => {
var tl = gsap.timeline(story, {
scrollTrigger: {
trigger: ".story__media",
scrub: true,
start: "top top",
end: "bottom bottom"
}
});
tl.from(".story__media img", {scale: 2, ease: "power2"})
});
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
gsap.registerPlugin(ScrollTrigger);
var tl = gsap.timeline({
scrollTrigger: {
trigger: ".story__media",
scrub: true,
//pin: true,
start: "-100%",
end: "+=200%"
}
});
tl.from(".story__media img", {
scale: 1.4,
ease: "power2"
})
<!-- language: lang-css -->
img {
display: block;
width: 100%;
max-width: 100%;
}
.story {
display: grid;
grid-template-columns: repeat(12, 1fr);
column-gap: 4px;
padding: 64px 0;
}
.story__media {
grid-column: 2 / span 5;
overflow: hidden;
}
.story__caption-wrap {
grid-column: 8 / span 4;
}
<!-- language: lang-html -->
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js?v=3.3.0-3"></script>
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- end snippet -->
答案1
得分: 1
你需要获取所有要进行动画的元素,遍历它们并将 trigger
设置为当前元素,而不是设置为一次性目标类(导致它们同时进行动画的原因)。类似这样:
<!-- 开始代码片段: js 隐藏: false 控制台: true Babel: false -->
<!-- 语言: lang-js -->
gsap.registerPlugin(ScrollTrigger);
const stories = document.querySelectorAll(".story");
stories.forEach((s) => {
var tl = gsap.timeline({
scrollTrigger: {
trigger: s,
scrub: true,
end: "bottom top"
}
});
tl.from(s.querySelector("img"), {
scale: 2,
ease: "power2"
});
});
<!-- 语言: lang-css -->
.intro {
height: 80vh;
display: grid;
place-items: center;
text-align: center;
border: 1px solid lightgray;
border-radius: 1rem;
margin-bottom: 10px;
}
img {
display: block;
height: 100%;
width: 100%;
object-fit: cover;
}
.story {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
padding: 1rem;
border: 1px solid lightgray;
border-radius: 1rem;
margin-bottom: 10px;
}
.story__media {
overflow: hidden;
border-radius: 1rem;
}
<!-- 语言: lang-html -->
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js?v=3.3.0-3"></script>
<div class="intro">
<h2>滚动查看魔法发生</h2>
</div>
<!-- 开始故事 -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>区块 1 的标题</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- 结束故事 -->
<!-- 开始故事 -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>区块 2 的标题</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- 结束故事 -->
<!-- 开始故事 -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>区块 3 的标题</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- 结束故事 -->
<!-- 结束代码片段 -->
英文:
You need to grab all the elements that you wanna animate, loop over them and set the trigger
to be equal to the current one, not to the class that target all of them at once (the reason all of them are being animated at the same time). Something like so:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
gsap.registerPlugin(ScrollTrigger);
const stories = document.querySelectorAll(".story");
stories.forEach((s) => {
var tl = gsap.timeline({
scrollTrigger: {
trigger: s,
scrub: true,
end: "bottom top"
}
});
tl.from(s.querySelector("img"), {
scale: 2,
ease: "power2"
});
});
<!-- language: lang-css -->
.intro {
height: 80vh;
display: grid;
place-items: center;
text-align: center;
border: 1px solid lightgray;
border-radius: 1rem;
margin-bottom: 10px;
}
img {
display: block;
height: 100%;
width: 100%;
object-fit: cover;
}
.story {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
padding: 1rem;
border: 1px solid lightgray;
border-radius: 1rem;
margin-bottom: 10px;
}
.story__media {
overflow: hidden;
border-radius: 1rem;
}
<!-- language: lang-html -->
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js?v=3.3.0-3"></script>
<div class="intro">
<h2>Scroll to see magic happen</h2>
</div>
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- Start Story -->
<div class="story">
<div class="story__media">
<img src="https://images.pexels.com/photos/16763202/pexels-photo-16763202.jpeg" alt="ALT TEXT">
</div>
<div class="story__caption-wrap">
<div class="story__caption">
<h2>Title of Block 3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</div>
<!-- End Story -->
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论