8000 [scroll-animations-1] CSS @scroll-timeline: Allow `<element-offset>` selector() to point to self · Issue #5884 · w3c/csswg-drafts · GitHub
[go: up one dir, main page]

Skip to content

[scroll-animations-1] CSS @scroll-timeline: Allow <element-offset> selector() to point to self #5884

@bramus

Description

@bramus

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?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0