I just blogged about a way to pass information from an element that had a view timeline on itself down to it’s descendent elements. The idea is to set up CSS custom properties with @property
and the @keyframe
would animate those, thus the descendent’s would have access to them.
It worked fine (noting that scroll-driven animations are, so far, only in Chrome).
But Bramus noted that another possibility there was to name the view timeline and have the children reference that instead. His video on this is informative.
The update to my original demo was pretty easy to do. Remember it had a section with a “pull quote”. The section had the view timeline, the pull quote is what I was trying to animate. So here I name the timeline (and note the scroll direction: block
means vertical in logical property world):
.has-pullquote {
animation: reveal linear both;
animation-timeline: view();
animation-range: cover 0% cover 100%;
view-timeline: --section-pullquote block;
}
Code language: CSS (css)
You have to name the timeline with a --double-sash
name like that, which in modern CSS parlance is referred to as custom ident. It looks like a custom property but it isn’t, it’s just a unique name.
Now that the timeline is named, any descendent can reference it for it’s own animation timeline. Again specific to my demo, I switched things up to work like this (just the basics):
blockquote {
/* Pull quote styling... */
animation: blockquote linear both;
animation-timeline: --section-pullquote;
}
@keyframes blockquote {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
Code language: CSS (css)
Here’s an updated demo using that technique instead of animating all custom properties.
The actual demo updates a few more things just to have a bit more of a play and try things out. Notably, one of the effects still required me to animate a custom property still. That’s because I’m animating the color-stop of a gradient, and since that’s just a part of a whole valid value, it really needs to be done as a custom property.
Still, most of the animation work was moved over to using a keyframe applied directly to the descendent element itself, which I think is a logical improvement and I think it’s very cool how you can do that.
Essentially: you can name a view (or scroll) animation timeline (view-timeline
or scroll-timeline
) and any descendent element can tap into it and base it’s animation off of that (animation-timeline
).
The fact that it works for descendents only is interesting to me. When I was playing with this to try to understand it, my first thought was to try to make a random element on the page have a scroll-timeline
and another totally random element on the page “listen” to that one for it’s animation-timeline
. I made them siblings and was confused why it wasn’t working. That ain’t gonna work, apparently, gotta have that parent/child thing going on. (Bramus’ video notes another gotcha: intermediary parents with overflow: hidden
ruining the effect, and a perfect solution: overflow: clip
).
I updated my playing to make it a parent/child relationship, and here’s that silly idea:
There you can see the “number” using the “scroller”s scroll-timeline
for it’s animation-timeline
and “animating” an integer value. If I wanted to take that integer and place it wherever on the page, it’s somewhat limiting because the parent container necessarily has overflow
on it so it scrolls.
It does make me wonder if anchor positioning or even some abuse of popover
would be able to pop it out of that constrained container, but that’ll have to be an exploration for another day.
Happy to see this post, Chris 🙂
Two remarks:
This should be “Now that the timeline is named, any descendent can reference it for it’s own animation timeline.”
For this the
timeline-scope
property was invented. It allows you to pull up (hoist) the scope of a named timeline to a parent.Demo: https://scroll-driven-animations.style/demos/carousel-with-markers/css/ (TIP: Hit the ℹ️ icon to see the explanation)
This is also covered in episode 5 of the video series: https://www.youtube.com/watch?v=Dk1YA8dCgE0&list=PLNYkxOF6rcICM3ttukz9x5LCNOHfWBVnn&index=5&t=444s