Skip to content
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-animations-2] Proposal: Time-based Keyframe Animations #4907

Open
shshaw opened this issue Mar 27, 2020 · 10 comments
Open

[css-animations-2] Proposal: Time-based Keyframe Animations #4907

shshaw opened this issue Mar 27, 2020 · 10 comments

Comments

@shshaw
Copy link

shshaw commented Mar 27, 2020

@keyframes are a great way to define animations, but the percentage-based declaration can be difficult to adapt to. Users familiar with GUI based animation programs or recreating existing animations in CSS can struggle with the conversion from absolute time to a percent.

Since we already have a <time> data type in CSS, could @keyframes be extended to support time based waypoints? This fits well within a standard animation timeline mental model which should make it easier for people to compose animations.

.box {
  animation: time-based-keyframes;
}
@keyframes time-based-keyframes {
  /* 0s 'frame' would be optional, same as `from` */
  0s { transform: rotate(0deg); }
  1s { transform: rotate(45deg); }
  2s { transform: rotate(45deg) translateY(100px); }
  /* Longest time duration = last 'frame', add pauses/delays with ranges */
  3s, 4s { transform: rotate(45deg) translateY(100px); }
}

This may not fit within the existing @keyframes model, but that would be preferable versus have a different model that could cause conflicts in the namespace.

Duration

animation-duration: auto would use the longest time declaration in the @keyframes. This could become the default value of animation-duration and would evaluate to 0s for standard percentage based @keyframes.

Scaling

The keyframe duration could be overridden by setting an exact duration, animation-duration: 2s, which would speed up or slow down the time-based @keyframes to match that duration. Much like in a video editor where you have a clip that's 10 seconds long, but you can speed it up so the duration of that video is only 6s or stretched out to 20 seconds. Doesn't change the original clip's 'length', but does change how the clip plays in the timeline.

Additionally, percent values in animation-duration could allow relative scaling of the keyframe defined duration.

/* Animation `@keyframes fade-out { 1s { opacity: 0 } }`*/
animation-duration: 200%; /* = 2s */
animation-duration: 50%; /* = 0.5s */

Having a standalone property for this like animation-timescale or animation-playback-rate would be useful, though expanding animation-duration for this "scaling" seems preferable.

Self-Contained Animations

Having time-based keyframes would make self-contained (“composed”) animations much easier. If the default duration becomes auto, then adding a composed animation to an element could be as simple as animation: my-keyframes where the duration, timing-functions and animated properties could all be declared within the keyframes.

.box { animation: scale-up; }

@keyframes scale-up {
  0s { animation-timing-function: cubic-bezier(0.5, 0, 0.5, 1); }
  1s { transform: scale(2); }
}

This containment would make animation design systems, exporting from GUIs, and CSS animation libraries easier to implement across a codebase.

WAAPI

Though outside of the CSSWG, it's worth considering how this could also improve WAAPI animations:

document.querySelector(".box").animate([
    { offset: "0s", opacity: 1 },
    { offset: "1s", opacity: 0 }
  ]); /* No duration needed */

"Polyfills"

Processors like Sass and PostCSS could implement this functionality by converting times to percentages given a duration ( @mirisuzanne was kind enough to create a Sass based mockup!
https://codepen.io/mirisuzanne/pen/jOPQdWw ) but native support would make CSS animation a lot more accessible to folks.

Conclusion

There are certainly opportunities to expand on this (relative times, delays, etc.), however the current scope seems like a realistic and reasonable addition which would make CSS animations easier to work with for users and tools.

CSS Animation 2 Spec for reference: https://drafts.csswg.org/css-animations-2

@birtles
Copy link
Contributor

birtles commented Apr 9, 2020

This sounds good. Note that #4862 is also suggesting adding an auto duration for scroll timelines and we have wanted that for groups too. In fact, the (very very draft) Web Animations level 2 spec introduces the intrinsic iteration duration concept and auto keyword for this.

Note that Web Animations (WAAPI) is a product of the CSSWG so it's fine to include that in scope. In fact, I think the best path forward here would be to work on the intrinsic iteration duration concept and scaling behavior such that it covers this case, the group case, and scroll timeline case.

For groups, in particular, I think the concept would also allow specifying child keyframe effects without any duration (only keyframe offsets), and then using the duration specified on an ancestor to calculate their final duration.

That is, similar to layout calculations, child nodes would pass up their resolved intrinsic durations, and bubble them up to the root, and then in a subsequent top-down traversal, we'd fill in the unresolved times based on the available time as well as scaling resolved times.

(In the very early days of planning Web Animations we had a number of proposals like this that we later realized were simply "flexbox, but for time".)

@flackr @majido Does #4890 harmonize with this in a way that covers groups too?

@nickLeidman
Copy link

I think it is a great idea, animations based on percentages always felt a little unwieldy. In the past I was destining complex CSS animations and i remember siting with notebook and calculator to figure out the percentages. Still have these long scripts somewhere.

But, not only this approach clarifies the timescale a little bit, for me adding something into a finished animation was a real pain, and this looks like a great solution for this as well! Basically, it looks like it comes down to just adding another keyframe at he end, no tedious recalculation of all percentages. Awesome, love that!

Another use case i see is for larger projects, with many animations. may be animation libraries, even. With custom properties controlling speed of animations becomes really just a "one line" solution. I imagine it to be something like that:

:root {
  --animationDuration: 100%;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --animationDuration: 50%;
  }
}

.animatedBlock {
  ...
  animation-name: myFancyAnimation;
  animation-duration: var(--animationDuration);
}

As I know in mobile operating systems (Android, for example) there is a control for animation speed. This proposal makes it easier to implement something like that in web aps.

@birtles
Copy link
Contributor

birtles commented Apr 12, 2023

@fantasai I notice you added Agenda + to this. Was there anything in particular you wanted to discuss?

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-animations-2] Proposal: Time-based Keyframe Animations, and agreed to the following:

  • RESOLVED: Draft up proposal for time-based keyframe selectors in Anim 2
The full IRC log of that discussion <TabAtkins> astearns: Anyone want to propose something for this, or just continue discussing in an issue?
<TabAtkins> fantasai: If we want to do, we can draft. If we'r enot sure, we can figure out the scope
<TabAtkins> miriam: I've heard lots of requests for this
<fantasai> TabAtkins: prsumably would work as we just discussed
<emeyer> TabAtkins: I presume it work in a way similar to what we just discussed
<TabAtkins> fantasai: Right, I think we have to think about these two together.
<TabAtkins> fantasai: So if we want to do this we can resolve it and figure out the issues together
<TabAtkins> miriam: is 100% the final time?
<TabAtkins> fantasai: That question is also relevant for the previous issue.
<TabAtkins> TabAtkins: Like is it duration, or duration+delay?
<emeyer> TabAtkins: Is it the duration, or is it the duration plus the dleay? Is that the question?
<flackr> q+
<TabAtkins> miriam: Or final keyframe
<astearns> ack astearns
<astearns> ack fantasai
<astearns> ack flackr
<TabAtkins> flackr: I think this is similar to range-based keyframes
<TabAtkins> flackr: Where they're converted to %s of the animation
<TabAtkins> flackr: The precedent we set is they don't set the range of the animation itself, they can go before beginning and after end
<TabAtkins> flackr: I can see if you use duration:auto if picks up the greatest duration specified in keyframes
<emeyer> TabAtkins: That would make sense if we ever do things like spring-timing functions
<TabAtkins> flackr: Yeah
<TabAtkins> flackr: But otherwise the default model should be the span is the animation duration, time values before/after that are clipped
<TabAtkins> +1
<TabAtkins> fantasai: That's different from... well what happens when you iterate?
<TabAtkins> fantasai: [missed]
<TabAtkins> flackr: Think it's consistent with range-based keyframes
<TabAtkins> flackr: They convert as if you have one iteration, and you shorten
<TabAtkins> fantasai: We'd do that here?
<TabAtkins> flackr: Yeah, don't think you want subsequent iterations to be different form earlier ones
<TabAtkins> fantasai: Feel like something's not clicking but not sure.
<TabAtkins> fantasai: But if we want to see this we should resolve on it and draft it, and see how all these keyframe types work together to make sure they're consistent
<TabAtkins> astearns: Anyone think we shouldn't work on it?
<TabAtkins> astearns: So options are (1) continue to work on details in the issue, or (2) put a draft in Animations 2
<TabAtkins> astearns: Anyone prefer leaving it in issue?
<TabAtkins> astearns: Anyone object to starting work on this in Anim 2?
<TabAtkins> RESOLVED: Draft up proposal for time-based keyframe selectors in Anim 2

@scottkellum
Copy link

+1 thank you for this issue and so carefully thinking it out. I created a Sass mixin to help me alleviate some of the issues in the thread but it would be very nice if this were adopted in some form.

@bramus
Copy link
Contributor

bramus commented Jan 10, 2025

I like the idea. Some questions though:

What happens if an author uses time-based keyframes and declares an animation-duration that is not auto?

For example, if the max keyframe is 10s what happens when :

  • The animation-duration is set to 5s?
  • The animation-duration is set to 15s?

Would the duration be ignored? Or would it determine things and act as a cutoff?

I would like to assume that the animation-duration would determine things in these cases and:

  • Cut the frames short when the animation-duration is shorter than the max <time> in keyframes: the animation stops after 5s
  • Generate the missing 15s keyframe

Or would the animation-duration speed things up / stretch things out? (I don’t think it should)

And also, what happens with the animation-fill-mode set to forwards? Does it use the last keyframe? Or does it use the last keyframe that was used? Put differently: in case of the 5s duration: does it fill to the 5s keyframe or the 10s one?

@shshaw
Copy link
Author

shshaw commented Jan 10, 2025

@bramus I wrote out some thoughts under "Scaling" in the original post. My initial thought was an animation with a last keyframe of 2s given an animation-duration of 1s would speed up playback 200%, much like speeding up a clip in a video editor. This is more consistent with how animation-duration currently works for percentage based keyframes. There's also some details on doing percentage based values for animation-duration as well.

Having duration acting as a cutoff is interesting, though has a lot of deeper implications. I'd be cautious of introducing that in animation-duration, and perhaps a separate property/properties that could control the "start" and "end" of the keyframes might be more appropriate.

@flackr
Copy link
Contributor

flackr commented Jan 10, 2025

I would prefer to to keep the keyframes (e.g. the animation would interpolate partially towards them) but still end the animation after the animation-duration. This is consistent with what we decided for out of range scroll-driven animation offsets #7825 and there are useful things you can do with this, e.g. you can show a preview snippet of a longer animation similar to the short 5s snippets when hovering over videos on video sites.

We could add animation-playback-rate: auto as a way to opt in to auto-scaling the playback rate to fit the keyframes to the duration.

@shshaw
Copy link
Author

shshaw commented Jan 10, 2025

animation-playback-rate: auto is nice for allowing scaling with animation-duration.

However per the current spec:

animation-duration: ... For time-driven animations, specifies the length of time that an animation takes to complete one cycle.

With that in mind, having animation-duration: <time> change the playback rate/speed to complete all the time-based keyframes within one cycle makes sense to me.

If the desire is for cutting an animation short, then a separate way for selecting the start and end of the keyframes seems appropriate for showing a segment of an animation. Haven't fleshed this out entirely, but initial thoughts would be:

  animation-segment: auto auto; /* Start at first keyframe, end at last keyframe. Equivalent to `animation-segment-start: auto; animation-segement-end: auto` */
  animation-segment: auto 5s; /* Clip a time-based keyframe animation to the first 5 seconds */
  animation-segment: 1s 2s; /* Clip time-based keyframes to only from 1s to 2s */
  animation-segment: auto 50%; /* Clip to the first half of the animation (regardless of time/percentage keyframes) */
  animation-segment: 50% auto; /* Clip to the last half of the animation (regardless of time/percentage keyframes) */

animation-duration: auto could take the animation-segment into account so animation-segment: auto 5s would be 5s duration and animation-segment: 1s 2s; would be 1s duration.

A property like this could be useful for percentage keyframes, time keyframes, and scroll animations.

@birtles
Copy link
Contributor

birtles commented Jan 13, 2025

I'd really like to see the interactions between these properties take parallels from layout.

Authors are already familiar with the different layout models and I really think we should design the animation properties to be "layout for time" such that things like delay mimic padding etc. Layout already has the same dynamic where dimensions are calculated based on constraints in both directions.

So, for the example of a non-auto duration that is less than a keyframe offset, I expect that would behave similar to a fixed height element with a child whose bottom edge stretches beyond the parent's height, i.e. it gets cut off.

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

No branches or pull requests

8 participants