-
Notifications
You must be signed in to change notification settings - Fork 747
Description
When animating an element based on the location of the element itself inside a scroll container using scroll-animations, you need to set a start
and end
. To configure this one needs an Element-based Offset.
When applying such an animation using the JavaScript it's pretty easy to set this up for many elements, as you can use a loop and refer to the current element by referring to its local var. See startScrollOffset
/endScrollOffset
in the code snippet below.
const $listView = document.querySelector('ul');
const $listItems = document.querySelectorAll('ul > li');
$listItems.forEach(($listItem) => {
// Slide-In
new Animation(
new KeyframeEffect(
$listItem,
{
transform: ["translateX(-100%)", "translateX(0)"],
},
{ duration: 1, fill: "both" }
),
new ScrollTimeline({
scrollSource: $listView,
timeRange: 1,
fill: "both",
startScrollOffset: { target: $listItem, edge: 'end', threshold: 0 },
endScrollOffset: { target: $listItem, edge: 'end', threshold: 1 },
})
).play();
});
While trying to recreate this using the CSS @scroll-timeline I've noticed that this this type of concise code is exactly possible as the <element-offset>
type requires a selector(<id-selector>)
. Because of that one has to create @scroll-timeline's for every individual li
@supports (animation-timeline: works) {
@keyframes fade-in {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
li {
transform: translateX(-100%);
animation: 1s fade-in linear forwards;
}
/* Scroll Timeline for first item */
@scroll-timeline list-item-1 {
source: selector(ul);
start: selector(#list-item-1) end 0;
end: selector(#list-item-1) end 1;
time-range: 1s;
}
#list-item-1 {
animation-timeline: list-item-1;
}
/* Scroll Timeline for second item */
@scroll-timeline list-item-2 {
source: selector(ul);
start: selector(#list-item-2) end 0;
end: selector(#list-item-2) end 1;
time-range: 1s;
}
#list-item-2 {
animation-timeline: list-item-2;
}
/* Scroll Timeline for third item */
@scroll-timeline list-item-3 {
source: selector(ul);
start: selector(#list-item-3) end 0;
end: selector(#list-item-3) end 1;
time-range: 1s;
}
#list-item-3 {
animation-timeline: list-item-3;
}
/* Now rinse and repeat for the next 100 elements … */
}
To not have to repeat that @scroll-timeline definition over and over again for each and every single li
, it'd be handy if the selector()
part in the <element-offset>
could be configured in such a way that it refers to the element being animated itself, e.g. this
or self
.
That way our code would become something like this:
@supports (animation-timeline: works) {
@keyframes slide-in {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
@scroll-timeline slide-in-in-parent-ul {
source: selector(ul);
start: selector(self) end 0;
end: selector(self) end 1;
time-range: 1s;
}
li {
transform: translateX(-100%);
animation: 1s slide-in linear forwards slide-in-in-parent-ul;
}
}
I see this as a huge benefit to the spec, as this would open up the way for animation/code reuse.
Would this be something worth pursuing, or am I overlooking something in the spec that would already allow this?