-
Notifications
You must be signed in to change notification settings - Fork 666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[css-scroll-animations] Rethinking declarative syntax for scroll-linked animations #6674
Comments
Having tinkered with Scroll-Linked Animations quite a lot (See here, here, here, here) I'd like to add some counterweight to the premise of this issue:
I only found myself in need of explicit offsets is some typical yet always very simple situations:
In all other cases I found myself grabbing to element-based offsets, as they're more dynamic. Additionally, when absolute offsets are needed they are mostly built using relative units (instead of absolute units), which also keeps them somewhat dynamic. (I know: the first linked to article uses them a lot but that's because of the structure of the two articles: only in the second article the concept of element-based offsets is introduced. If I were to rewrite some examples from the first article (such as the image gallery) I'd use element-based offsets for it, as such an implementation would adapt itself to the number of slides/images)
To me, the root cause here is the fact that This shortcoming of |
The need for a |
Thanks for your feedback @mirisuzanne. It's great to see how you approach this from CSS up, whereas the spec as it stands right now was clearly written from a JS-first stance, and then translated to CSS. If you don't mind, I'm gonna keep on asking questions here, to fully grasp how this adjusted proposal would work in practice.
I see that However, I do see a reduced number of identifiers with this: main { /* Identifier 1 */
container-type: size;
container-name: page-layout; /* Identifier 2 */
}
.foo {
animation-timeline: scroll(block, page-layout); /* Identifier 2, again */
} vs. main { /* Identifier 1 */
container-type: size;
container-name: page-layout; /* Identifier 2 */
}
@scroll-timeline my-timeline { /* Identifier 3 */
source: selector(main); /* Identifier 1, again */
direction: block;
}
.foo {
animation-timeline: my-timeline; /* Identifier 3, again */
} That's one identifier less, so I guess that's a win there :) On the other hand: when using a main { /* Identifier 1 */
container-type: size;
container-name: page-layout; /* Identifier 2 */
scroll-timeline-direction: block;
scroll-timeline-name: main-scroller: /* Identifier 3 */
}
.foo {
animation-timeline: scroller; /* Identifier 3, again */
} As a sidenote: in the snippet above it feels weird to have three identifiers linked to one and the same element. Should more future additions to CSS also require a name, the list of properties with a set name would keep on growing. Winging back to main {
container-type: size;
scroll-timeline-direction: block;
}
@container selector(main) (block-size > 12em) {
/* … */
}
.foo {
animation-timeline: selector(main);
} Feels much neater, no? (See this as an addendum/alternative syntax, not a replacement for giving names via the
Of course, and we should embrace that where possible. While working with scroll-timeline (the current version) I often found myself targeting three things. Some using a selector, others using
See for example https://codepen.io/bramus/pen/QWGbOBQ which sports a horizontal scrolling section. The code targets:
With the adjustments, I guess this be the correct way to do it:
That's correct?
For the code example referenced above that does seem to work out (if my understanding is correct there) but for a typical ScrollSpy it would not. See a reduced https://codepen.io/bramus/pen/3d544d1a7866478fae98ef39cf4f9b7f demo where the navigation <div>
<ul id="s">
<li id="s1">Slide 1</li>
<li id="s2">Slide 2</li>
<li id="s3">Slide 3</li>
<li id="s4">Slide 4</li>
</ul>
</div>
<nav>
<a href="#s1" id="d1">Go to Slide 1</a>
<a href="#s2" id="d2">Go to Slide 2</a>
<a href="#s3" id="d3">Go to Slide 3</a>
<a href="#s4" id="d4">Go to Slide 4</a>
</nav> For example: as This would be something I'd miss to be honest.
Often it is also required to perform an animation as an element slides into the scroller, or slides out of it — e.g. not only while it is in view. See https://codepen.io/bramus/pen/oNYEgEQ for example where elements are animated as the enter/exit the scroller. How would this be covered in this proposal? I guess it has to do with the The Or would one need a combination of both these properties? Put differently: is it possible to target these 4 typical timelines?
Must say I kinda liked the re-use of the threshold concept (from
Is it possible that there's a typo there and that the very last words should be “… 100% (contain).”? |
@bramus Responding to a few of your comments...
Not quite, the scroll() function looks up to the nearest scroll container ancestor, it doesn't have to be the parent.
Yes. Looking at your example, maybe we should have a way for an element to grab the nearest ancestor view-timeline, same as we do for the nearest ancestor scroll-timeline?
This seems like it ought to be a transitions demo rather than an animations demo, to be honest! Though I'm not sure how we can capture the state there to make it transition... a problem for another day, I guess. We could make the view timelines global to the page, but we'd probably want to make sure that multiple view timelines that have the same name are prioritized by proximity (similar to how counters work).
Interesting! We should definitely make that easily possible somehow. Have to think about that...
Good catch. Should be 0% (cover). But we're open to arguments in favor of a different default. :) |
I support this rethink (I never liked BTW, what happens if we access
On the one hand, this is Weird and New (boo!). On the other hand, the mode of operation for scroll-linked animations is to base the timeline state on layout information from the previous frame. Assuming we're sticking with that, global/broad names seem possible. |
@andruud I think that we would change the JS interface as well to have ViewTimeline and ScrollTimeline as separate timeline types that can be constructed with arguments that roughly match the CSS syntax, except allowing specifying any element as the target as the JS API allows with ScrollTimeline today. |
The CSS Working Group just discussed
The full IRC log of that discussion<TabAtkins> Topic: Rethinking delarative scroll-based animations syntax<TabAtkins> github: https://github.com//issues/6674 <Rossen_> github: https://github.com//issues/6674 <TabAtkins> miriam: So we were looking at scroll-linked animations (sla) as part of a bigger thing <TabAtkins> miriam: Was looking at container-based interpolations, and ideally being able to interpolate values *in* the cascade rather than juming out to animations which override everything <fantasai> See full discussion at https://wiki.csswg.org/ideas/timelines ; this crosses multiple issues <TabAtkins> miriam: current sla proposal seems JS focused and later ported to CSS, so we wanted to discuss this <fantasai> (into which we posted pieces of that overal proposal) <TabAtkins> miriam: Rethinking how we could make sure SLAs, already in prototype, fit into our future plans for animations/inteprolation <TabAtkins> miriam: several parts <fantasai> SLA = Scroll-Linked Animation <TabAtkins> miriam: Animations based on where you are in the scroll position of a container <TabAtkins> miriam: So 0% - 100%, linked to an animation progress <TabAtkins> miriam: Proposal is thus for an animation-timeline property (already in the SLA proposal), defaults to auto, but can be given a scroll() function. <TabAtkins> miriam: Defaults to looking at nearest scrollable ancestor, you can specify what direction you want to listen to. <TabAtkins> miriam: And can opt to look at root scroller, or a given container's name (specified in another property) <Rossen_> q? <TabAtkins> miriam: An alt to that syntax is that instead of a scroll() function, could break out scroll-timeline-* properties <fantasai> s/another property/container-name property, re-using from the @container query proposal/ <TabAtkins> miriam: Using the function in animation-timeline seemed like a an extensible way to do more timeline types in the same property <TabAtkins> flackr: Is there a functional difference there? You could specify scroll() or a timeline name in animation-timeline? <TabAtkins> miriam: right <TabAtkins> flackr: So even if it is a function, we have the ability to specify other timeline types with a timeline name <TabAtkins> miriam: So I think that's all handled by the larger proposal for SLA <flackr> q+ <TabAtkins> miriam: Another thing - wanting to naimate on elements coming in or out of view. These element-based timelines work a little differently <TabAtkins> miriam: Proposing view-timeline-* properties <TabAtkins> miriam: view-timeline-name specifies the name of the timeline corresponding to the element coming in or out of view <TabAtkins> miriam: view-timeline-inset to adjust how quickly it considers itself in view <TabAtkins> miriam: and view-timeline-fit gives the baseline for where 0% is - start when they start to come into view, or start when fully into view <TabAtkins> miriam: Also a question for if we need a timeline for that in-between space, between when it start to come into view and is fully in view <TabAtkins> miriam: In terms of scroll-linnked timelines, were thinking these timelines would be visible to descendants and siblings; scope is attached to descendants of the parent <TabAtkins> fantasai: One suggestion was to expose it to the whole document <TabAtkins> fantasai: Coudl do this <TabAtkins> fantasai: But it's important to resolve name conflicts with closer in the tree, not later in stylesheet or tree <smfr> q+ <TabAtkins> fantasai: Multiple elements styled with the same timeline name should animate independently <Rossen_> ack flackr <fantasai> s/elements/subtrees/ <flackr> https://github.com//issues/4912 <TabAtkins> flackr: We did have use-cases initially with scroll-timeline where author wanted to specify for a certain numer of pixels of scroll (largely for parallax effects, but we had others) <TabAtkins> flackr: I assume that to do this with the new proposal you'd need an element that corresponded to the number of pixels you want to animate over? <TabAtkins> flackr: Because the scroll() function is always from 0 to max scroll <TabAtkins> flackr: And specifying in terms of %s is dependent on layout which is complicated <TabAtkins> miriam: I don't think we covered that use-case, we'll have to think abou tit <TabAtkins> smfr: A few things <TabAtkins> smfr: For animations that run when an element comes into view, there's subtlety what designers want <Rossen_> ack smfr <TabAtkins> smfr: Possibly some hysteresis; if you wobble it around the trigger point you want a looser organic feel <TabAtkins> smfr: So feel designers will want more specific control <TabAtkins> fantasai: I think you're mixing up scroll-linked and scroll-triggered animations <TabAtkins> fantasai: SLA, the scroll position *is* the timeline. if you move the scroller it scrubs the animations backwards <TabAtkins> fantasai: scroll-triggered is a timed animation that triggers when it comes into view <TabAtkins> fantasai: the SLA in general is not targetting that use-case <TabAtkins> smfr: I think I've seen examples that are scroll-linked but do have hysteresis <TabAtkins> smfr: Some Apple pages have things that are linked to scroll position but still not precisely linked <TabAtkins> smfr: Some time delay <TabAtkins> flackr: I've seen this too, some examples of animations that are specifically lagged behind the timeline to provide some extra smoothness <TabAtkins> smfr: So my problem is just making sure it's rich enough to address designer use-cases, or else they'll still just write JS <TabAtkins> Rossen_: So are your examples addressed more if you have some sort of easing function that is part of the change? <TabAtkins> Rossen_: So you have some easing between hops? <TabAtkins> smfr: I don't think easing is enough; I think there has to be some time-based aspect <smfr> https://www.apple.com/iphone-13-pro/ <TabAtkins> flackr: Could just be a lot of scroll triggers with easing... <TabAtkins> smfr: Here's an example <TabAtkins> smfr: There's an image showing the camera bumps, it's somewhat scroll-linked, but then it's sticky... <TabAtkins> fantasai: We do have the *-inset property, which gives a *spatial* delay <TabAtkins> flackr: Further down where it says "shoot it, cut it, ship it" seems to be the effect Simon's talkinga bout <TabAtkins> Rossen_: So we can record Simon's concern in the issue, but I want to kepe the convo moving <TabAtkins> smfr: Is it possible for an SLA to affect the size of the scrolled content, so we get circularity? <TabAtkins> flackr: Yes, this has always been the case. We choose to handle it similar to :hover examples <TabAtkins> flackr: You get the scroll position at the start of the frame, and if you change the size, the next frame will get an updated animation progress. <TabAtkins> smfr: So that'll be specified in terms of the HTML event loop <fremy> +1 to what florian just said, I was about to say the same <fantasai> florian: ... <fantasai> TabAtkins: Nothing in the spec to that effect, could have it flicker madly under the cursor <Rossen_> q? <florian> s/.../seems a little worse than :hover, as it can loop without further user interaction/ <TabAtkins> flackr: Back to the lag thing, we could have something like transitions where the animation progress eases over time rather than immediately updates. WE'd have to look into it <fantasai> https://drafts.csswg.org/scroll-animations-1/ <TabAtkins> fantasai: Worth reminding that there is a SLA ED that was already adopted <TabAtkins> fantasai: Our issue was just about redesigning how the declarative syntax works <flackr> q+ <Rossen_> ack flackr <fantasai> fantasai: question is, do we want to make changes going in this direction <TabAtkins> flackr: Overall I think this is a nice change. There's some use-cases we shoudl consider that we might be dropping, but I'm supportive of this overall direction. <TabAtkins> flackr: We should probably change the JS API to roughly match the proposed CSS timelines; view-timeline and scroll-timeline as things you con construct, but also keep the arbitrary-element selection that the JS API can allow <Rossen_> ack flackr <TabAtkins> fantasai: Yeah we didn't review the JS part at all; figured we'd hash this out and bring it back to JS <fantasai> s/bring/then bring <TabAtkins> Rossen_: Last comments or objections? <TabAtkins> RESOLVED: Adopt fantasai/miriam's new direction for the declarative side of scroll-linked animations <TabAtkins> RESOLVED: Add flackr as editor to scroll-animations, move Majid to Former <TabAtkins> [other editors are all still fine] |
As pointed out by @andruud and @flackr above I also think it's preferable to keep the JS and CSS interfaces tied to each other. Right now this is the case: if you know how one works you also know the other, as they share the same concept/approach. @fantasai Regarding those "element slides into view"-animations. Note that it can also be about a portion of that element, e.g. "only start when a quarter into view" or "be finished when 75% in view". I've done so in https://www.bram.us/2021/03/04/the-future-of-css-scroll-linked-animations-part-2/#demos--revealing-images for example where the animation runs from 50% into view to 100% into view. Above that several animations can be attached to several phases of a timeline. See https://www.bram.us/2021/03/04/the-future-of-css-scroll-linked-animations-part-2/#demos--contact-list-revisited for example, where there are different enter and exit animations on the same element. 💡 To implement this it looks like a good idea to me to have one shared I'm thinking of two new properties here:
The adjusted syntax for the https://www.bram.us/2021/03/04/the-future-of-css-scroll-linked-animations-part-2/#demos--contact-list-revisited example would then become: @keyframes animate-in {
…
}
@keyframes animate-out {
…
}
ul {
overflow-y: scroll;
}
li {
view-timeline: li-in-ul;
view-timeline-fit: cover;
}
li > * {
animation:
animate-in 1s linear forwards,
animate-out 1s linear forwards;
animation-timeline:
li-in-ul,
li-in-ul;
animation-timeline-phase:
enter,
exit;
animation-timeline-thresholds:
25% 100%,
100% 25%;
} In this example:
🤔 Braintwist: If these new properties would exist, is 🤔 Braintwist on the braintwist: Say In that case I'm sliding back to a syntax using an edge and a percentage, which is awfully similar to animation-timeline: some-element-in-a-scroll-container;
animation-timeline-phase-start: end 0%; /* Start animation when the watched element is sitting at the end edge, with 0% in view*/
animation-timeline-phase-end: 50%; /* Have animation be finished by the time the watched element is in the middle of the scroll-container*/ To combine these in the Thinking of (Apologies for freewheeling here. My mind is playing ping-pong with itself when it comes to Scroll-Linked Animations 😅) Looking a bit broader, I think it's advised to also keep Scroll-Triggered Animations in mind while figuring out the syntax for Scroll-Linked Animations [edit: it is], so that we don't hit a wall when they are being considered. I'm seeing options with something like |
Here's a good example where animations a kinda-scroll-linked but not directly: https://codepen.io/isladjan/pen/abdyPBw |
…le system. r=emilio This patch adds the animation-timeline longhand property. For shorthand, we will do that in the next patch. This patch includes the aut-generated code in devtools/shared/css/generated/properties-db.js, by `./mach devtools-css-db`. Note: 1. we will use this property in Bug 1676791. For now, only make sure we parse it and serialize it correctly. 2. The syntax of animation-timeline may be updated, based on the spec issue: w3c/csswg-drafts#6674. However, it's not a big problem to update it later, so we still can prototype this property based on the current version of spec. Differential Revision: https://phabricator.services.mozilla.com/D126450
…le system. r=emilio This patch adds the animation-timeline longhand property. For shorthand, we will do that in the next patch. This patch includes the aut-generated code in devtools/shared/css/generated/properties-db.js, by `./mach devtools-css-db`. Note: 1. we will use this property in Bug 1676791. For now, only make sure we parse it and serialize it correctly. 2. The syntax of animation-timeline may be updated, based on the spec issue: w3c/csswg-drafts#6674. However, it's not a big problem to update it later, so we still can prototype this property based on the current version of spec. Differential Revision: https://phabricator.services.mozilla.com/D126450
I stand with a need to allow for global scroll timelines. We have a use case in mind that synchronizes scroll position of a scroller with transform of an element which is not an ancestor of the scroller. |
@smfr For these use cases I propose we properties similar to transition timing functions (transition-duration, transition-timing-function, transition-delay) which will specify a delay over which the scroll input will plug in to the timeline. E.g. for view-timeline: view-timeline-transition-duration: <time>
view-timeline-transition-timing-function: <easing-function>
view-timeline-transition-delay: <time> Then for the above use case the developer would simply specify a |
I'm not clear what it means to have a duration that is simultaneously based on a scroll-timeline and a set time? How are those meant to interact in your proposal? |
The duration in my proposed property is the length of time it takes the scroll based timeline to catch up to scroll position changes. Here's an example hacked together with javascript using a custom property transition to represent the delayed transition value being plugged in to the timeline: |
What are the plans for further pursuing this new syntax? I'm definitely open to all these changes, but with the Chromium Implementation breaking (and not being fixed) I'm hoping to pick up the new syntax in due time. (And, truth be told, I'm currently cancelling speaking engagements on the Happy to join a session to exchange additional ideas (such as the proposed |
Same question as @bramus asked. I'm also waiting for the update of the syntax in the spec. Due to this spec issue, I implemented |
I'm working on rewriting the spec with @flackr's help in the rewrite.bs file in the repo; I'll propose replacing the existing draft once it's a bit more complete. I've also opened up some follow-up issues:
Please redirect your specific comments there, I'll keep this one open for switching up the overall direction and close it out once we're ready to fold in those edits. :) Thanks!! |
This patch adds the animation-timeline longhand property. For shorthand, we will do that in the next patch. This patch includes the aut-generated code in devtools/shared/css/generated/properties-db.js, by `./mach devtools-css-db`. Note: 1. we will use this property in Bug 1676791. For now, only make sure we parse it and serialize it correctly. 2. The syntax of animation-timeline may be updated, based on the spec issue: w3c/csswg-drafts#6674. However, it's not a big problem to update it later, so we still can prototype this property based on the current version of spec. Differential Revision: https://phabricator.services.mozilla.com/D126450
This patch adds the animation-timeline longhand property. For shorthand, we will do that in the next patch. This patch includes the aut-generated code in devtools/shared/css/generated/properties-db.js, by `./mach devtools-css-db`. Note: 1. we will use this property in Bug 1676791. For now, only make sure we parse it and serialize it correctly. 2. The syntax of animation-timeline may be updated, based on the spec issue: w3c/csswg-drafts#6674. However, it's not a big problem to update it later, so we still can prototype this property based on the current version of spec. Differential Revision: https://phabricator.services.mozilla.com/D126450
Overview
@mirisuzanne and I reviewed the Scroll-linked Animations ED this week. We have some concerns (which are at a high level similar to Robert O'Callahan's concerns with the initial proposals for “CSS Snap Points” that became the current CSS Scroll Snap Module):
We'd like to propose a replacement of the declarative syntax in this module that addresses these problems. Note: This is part of our larger proposal rethinking various features for animation timelines and interpolation and how to fit them all together.
Our suggestion splits scroll-linked animation timelines into two types: those linked to the scroll timeline as a whole, and those linked to the portion of it in which a particular element participates.
Animations linked to scroll progress as timeline
These are animations whose timeline goes from 0% to 100% based on the scroll position of an ancestor scroll container.
animation-timeline: scroll()
The idea is to use an inline functional notation to identify the timeline using the
animation-timeline
property, expanding the property's syntax as follows:auto
is the initial value ofanimation-timeline
, and behaves as animations have always done, triggering on application of the animation and lasting for the specified duration and delay.nearest
references the nearest ancestor scroll containerroot
references the main viewport scroller<container-name>
references thecontainer-name
property: it filters the lookup to the nearest scroll container with the givencontainer-name
. (See css-contain-3.)block
; the default scroll container lookup isnearest
animation-timeline: NAME
Alternately, some scroll-timeline properties could be defined, which when applied to a scroll container would allow naming its timeline for a more indirect but reusable approach.
Such named scroll timelines would be referenceable by name from the
animation-timeline
property.Animations linked to view progress as timeline
Often animations are desired to start and end while a particular element is in view within the scroller. This timeline is essentially a snippet of the scroller's complete timeline, with 0% and 100% pinned to the moment the element comes into view and the moment it leaves view.
view-timeline-name
- Specifies a name for this element's in-view timeline, so that it can be referenced by descendant and sibling elements as their animation-timeline.view-timeline-inset
- Specifies an inset (positive) or outset (negative) adjustment of the scrollport when considering whether the element is in view. auto indicates to use the value of scroll-padding. Initial value is zero. Percentages are with reference to the scrollport.view-timeline-fit
- Specifies whether the in-view timeline is measured from the moment any part of the box comes into view until all parts leave it (cover/0%) or whether it is measured from the moment all parts of the box come into view until any part leaves it (contain/100%). Initial value is 0% (cover).Scope of Scroll-linked Timelines
The scope of a scroll-linked timeline (which elements can call it by name via animation-timeline) is defined as:
This basically means its scope is attached to its parent, but the parent can't use it. In case of multiple timelines with the same name being in scope, the timeline associated with its nearest ancestor wins.
(It might also be useful to allow the scope to expand outside this parent, giving ancestors and far cousins access to the timeline across the document. In all cases the timeline reached via the closest ancestor should win in case of conflict. But this kind of global scoping from descendant elements might be difficult to implement.)
The text was updated successfully, but these errors were encountered: