Skip to content

[css-animations-2][scroll-animations-1] Keyframe ordering and ordering requirements #8507

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

Closed
flackr opened this issue Feb 28, 2023 · 1 comment · Fixed by #8705
Closed

[css-animations-2][scroll-animations-1] Keyframe ordering and ordering requirements #8507

flackr opened this issue Feb 28, 2023 · 1 comment · Fixed by #8705

Comments

@flackr
Copy link
Contributor

flackr commented Feb 28, 2023

Overview

We need to define the order of keyframes from CSS animations and any requirements when constructing JS animations. Prior to timeline range keyframe selectors we have the following rules:

css-animations-2 Section 3. Keyframes performs a stable sort by offset (step 6), and merges keyframes with matching keyframe offset, timing function and composite (step 6.4). The result is exposed via the web-animations-1 getKeyframes method.

web-animations-1 Section 6.6.3. Processing a keyframes argument procedure to process a keyframes argument step 6 throws a TypeError if the supplied offsets of the keyframes are not sorted.

With timeline range keyframe selectors the order of keyframes is not known until after layout and may change with changes to the layout. As such, we have to decide how to handle this.

I wrote a short demo to show the observed keyframes at https://jsbin.com/zofukin/edit?html,css,js,output

Proposal

For css animations:

  1. just as differences in composite and the timing function do not allow two keyframe blocks to be merged, we should consider named range offsets to only be mergeable with the exact same specified named range offset.
  2. Keyframes should continue to be sorted by a stable sort, though it will need to be a sort of their computed offsets.
  3. Where do we sort keyframes whose offsets are not computable? They could be kept in their stable position ignoring offset or they could be effectively removed not appearing in getKeyframes. Naively, I'd propose keeping them in their stable sorted position and visible in the API.

For web animations, we never modify the passed in keyframes. They are returned in the order specified with specified offsets. We can't enforce the ordering requirement as strictly. We could do one of the following:

  • Only require ordering of keyframes with overall percentage offsets, allow other keyframes in any order.
  • Require ordering of keyframes within each named offset range. E.g. two keyframes on the cover range must be ordered with respect to each other. Though this gets more complicated when you consider that offsets will support calculations in the future.

I lean towards the first since calculations will also break the ability to ensure that order is correct when specified.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-animations-2][scroll-animations-1] Keyframe ordering and ordering requirements, and agreed to the following:

  • RESOLVED: Collapse keyframes with same specified offset to the earlier one, then pull percentage-only keyframes to the front and sort them
The full IRC log of that discussion <fantasai> s/Topic/Subtopic/
<fantasai> s/Topic/Subtopic/
<emilio> flackr: css-animations defines that there's a sorting of keyframes by offset
<fantasai> i/scribenick/Topic: Scroll Animations/
<emilio> ... timeline-range keyframes have effectively dynamic offsets
<emilio> ... further, web-animations requires keyframes to be sorted and throws if not
<emilio> ... proposal is for css animations if you look at keyframes you'll sort by the computed offset which means that the keyframe order can switch depending on layout offsets
<emilio> ... we shouldn't merge keyframes with same computed offset but different specified offsets
<emilio> ... there's an exception already for different composite modes and easing
<emilio> ... if you have a not-computed offset
<emilio> ... I'm proposing we just keep them in the stable sort order relative to the other keyframes around them
<emilio> ... so basically you do a stable sort but keyframes with no offset are not comparable
<emilio> q+
<emilio> flackr: there'd be no changes for web animations, what you pass is what you get, and we'd relax the requirement to specify them in order
<emilio> ... so that only fixed offsets need to be sorted
<Rossen_> ack fantasai
<emilio> fantasai: so you're proposing that whatever keyframes get passed in and if they don't have a resolvable offset do they get dropped?
<emilio> flackr: they're dropped from the animation but getKeyframes would still return them as described above
<Rossen_> ack emilio
<fantasai> emilio: Does this mean that calling getKeyframes now needs to do a layout update, rather than just styling?
<fantasai> flackr: yes, if the animation has range-based keyframes, it needs a layout update...
<fantasai> flackr: I believe that at least Chrome didn't differentiate between style and layout in this case
<fantasai> emilio: I'm pretty sure we do
<fantasai> emilio: Chrome doesn't have such a strong difference between update style vs layout
<fantasai> emilio: but we do have that difference
<fantasai> emilio: although container queries make that tricky
<emilio> fantasai: would it make sense not to do the layout-based sort?
<emilio> fantasai: so percentage-based keyframes are sorted but the others remain stable
<fantasai> emilio: I think that might be slightly preferable
<fantasai> emilio: the less we need to update for DOM APIs the better
<ydaniv> q+
<chris> regrets+ lea
<emilio> fantasai: why are we sorting these at all? Can we have the API not sort them?
<emilio> flackr: for WebAnimations it asserts that they're sorted, which we need to relax
<emilio> ... for CSS animations it's spec'd that we'd sort the keyframes by the percentage specified
<emilio> ... this is observable and it'd be hard to know whether it's compatible to change that
<emilio> fantasai: what if we zero out the dynamic offsets when sorting so that we have a canonical order?
<emilio> ... if there's a percentage offset we sort by that but for range we treat as zero
<emilio> flackr: I feel like if we treat range separate we can just leave them in the specified order
<emilio> ... I think the main reason keyframes are sorted by percent is for merging and we don't want to merge these
<emilio> YehonatanDaniv: the only case offsets could change dependent on layout is changing ?? to cover
<emilio> ... I think that's the only case which is kind of minor
<emilio> flackr: anything other than cover computes its offset based on the timeline
<Rossen_> ack ydaniv
<fantasai> flackr: cover is the only case where the % specified is equivalent to the percentage in the timeline
<fantasai> flackr: otherwise the % is dependent on layout
<fantasai> flackr: e.g. range of 100% is dependent on the element size
<fantasai> YehonatanDaniv: larger or smaller than viewport?
<fantasai> flackr: any change in the element's height changes what 'enter 100%' results in
<fantasai> YehonatanDaniv: but that doesn't change the order of keyframes
<fantasai> flackr: ah, yes. If you have keyframes of multiple ranges specified
<fantasai> YehonatanDaniv: I think if the only edge case is missing one of the 1st three with cover, then reasonable not to update the order of the keyframes according to layout changes
<bramus> q+
<fantasai> YehonatanDaniv: we have duration and currentTime update, but order of keyframes doesn't need to change in most cases
<fantasai> flackr: but the question is what should spec say about order of keyframes?
<fantasai> YehonatanDaniv: I think everything else still holds, we have logical order of entry/contain/exit, and then entry-crossing/exit-crossing
<fantasai> flackr: there's overlap among those phases, and cover covers all of them
<fantasai> YehonatanDaniv: cover is the special case
<fantasai> flackr: entry-crossing and exit-crossing are also special
<fantasai> flackr: one possibility is we could have sort by range name and then percentage
<fantasai> flackr: that defines a DOM ordering
<fantasai> flackr: or we could leave them as specified in the CSS
<fantasai> flackr: which is consistent with what we do when keyframes have different easings or composit modes
<fantasai> flackr: they stay in their specified order
<fantasai> flackr: so in the absence of any reason to sort we use the specified order
<fantasai> YehonatanDaniv: ok, by range name and offset, but need to clarify regarding special cases
<fantasai> flackr: the other reason that sorting matters is it affects which keyframe values are active for a particular range
<fantasai> flackr: if 2 keyframes compute to 20%, when you're after 20%, which keyframe's values are you getting?
<fantasai> flackr: if one says 'bg: green' other is 'bg: blue', need to know which is later to know what color to get
<fantasai> flackr: my proposal is in all complex cases we use specified order
<fantasai> flackr: that removes layout order, and produces a well-defined animation
<fantasai> YehonatanDaniv: consistent also with [missed]
<fantasai> flackr: consistent with what we do with easing and composit mode
<fantasai> bramus: Also wanted to point out order can change if size of scroller changes
<emilio> bramus: wanted to point out that order of the keyframes can change if size of scroller changes
<fantasai> bramus: e.g. 'enter 100%' and exit animation starts when scroller becomes too small
<Rossen_> ack bramus
<fantasai> bramus: authors can predict what happens, so I'm in favor of this proposal
<emilio> fantasai: I wanted to ask what the proposal is? Don't sort other than the percentage based ones? If two keyframes have the same offset even in different phases we don't merge them?
<emilio> flackr: we won't merge if they have the same computed offset
<emilio> fantasai: even if they have the same specified offset?
<emilio> flackr: we can merge then, it's not complex and is consistent with the expectations for other animations
<emilio> fantasai: I think we could propose that keyframes with the same specified offset are merged
<emilio> fantasai: what happens if there's interleaved keyframes and ranged?
<emilio> flackr: the index of the specified keyframe is the secondary sort order
<emilio> fantasai: so say I have 0%, entry, 0%, entry, 20%, entry, 50%
<Rossen_> q?
<fantasai> 20%, entry 50%, 0%, entry 0%, entry 6em
<Rossen_> ack fantasai
<emilio> flackr: I was wondering if we could be really naive and use stable sort where values are equal if any value has ranges
<emilio> ... so only the 0% will move before the 20%
<emilio> flackr: for applying the animation later we need to sort by computed offset
<emilio> fantasai: right but you want percentages in order, but ranges don't matter
<emilio> ... so do you ?? or move all the percentages first?
<emilio> flackr: I think percentages at the beginning would be simplest
<emilio> fantasai: I think otherwise you need to chop up the list and sort the fragments
<Rossen_> 0%, 20%, entry 50%, entry 0%, entry 6em
<fantasai> Percentages at the beginning option: 0%, 20%, entry 50%, entry 0%, entry 6em
<fantasai> Segmented list option: 0%, entry 0%, entry 6em, 20%, entry 50%
<emilio> flackr: my concern with the segmented option is that percentages are not guaranteed to be sorted among them
<emilio> fantasai: I'm not sure it makes sense, I'm saying "I'm a complex list so my order is whatever"
<emilio> flackr: I'm not sure it makes sense to do that
<emilio> q+
<fantasai> s/whatever/that of the most recently-specified raw percent keyframe/
<fantasai> emilio: I was going to say that seems more simple and intuitive to me
<Rossen_> ack emilio
<fantasai> emilio: put percentages at the beginning, then sort the rest
<fantasai> PROPOSAL: Collapse keyframes with same specified offset to the earlier one, then pull percentage-only keyframes to the front and sort them
<emilio> RESOLVED: Collapse keyframes with same specified offset to the earlier one, then pull percentage-only keyframes to the front and sort them
<fantasai> Rossen_: OK, we're resolved. As you get more experience with this, let us know if it works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants