You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[web-animations-2][css-animations-2] Set of actions for animation triggers #12611
A probable outcome of #12336 is having animation triggers specify a set of actions which they will perform on their attached animations.
I think @tabatkinstable is a good place to start so I'll copy-paste it here with slight modifications:
Keyword
Initial
Playing
Paused
Finished
play-forwards
Set playback rate positive, play()
Set playback rate positive
(same as initial)
(same as initial)
play-backwards
Set playback rate negative, play()
Set playback rate negative
(same as initial)
(same as initial)
play-alternate
play()
Negates playback rate
play()
Negates playback rate, play()
pause
nothing
pause()
nothing
nothing
play-pause
play()
pause()
play()
play()
reset
nothing
set progress to 0, pause()
(same as playing)
(same as playing)
restart/replay
play()
set progress to 0
set progress to 0, play()
set progress to 0, play()
The main difference between Tab's table and the above is the following:
reset on a playing animation will, in addition to setting progress to 0, pause the animation.
I think it might also be useful to have a play keyword:
The Houdini Task Force just discussed [web-animations-2][css-animations-2] Set of actions for animation triggers, and agreed to the following:
RESOLVED: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animation
The full IRC log of that discussion
<TabAtkins> flackr: we've set up our triggers such that a named trigger has some set of associated actions
<TabAtkins> flackr: UI events, or enter/exit for timelines
<TabAtkins> flackr: there are, i think, 3 ways to associate them with an animation behavior
<TabAtkins> flackr: 1) in trigger definition, specify this action has this behavior
<TabAtkins> flackr: 2) like ydaniv proposed, on the animating element you specify the behavior, and there's something about exit behaviors
<TabAtkins> flackr: the only way i can make this make sense is that the exit has another behavior in the animation-trigger proeprty
<TabAtkins> flackr: 3) an explicit syntax, maybe functional, in animation-trigger that links a trigger name to an animation behavior
<TabAtkins> flackr: i think third is most generic and conceptually simple
<TabAtkins> flackr: it leave sit so triggers don't mention animations
<TabAtkins> flackr: and we can do more stuff with triggers in the futre
<TabAtkins> ydaniv: in option 2 i allowed 2 triggers, was continuing the line tab and elika took
<TabAtkins> ydaniv: but if we go back to just allowing one trigger, you spec the trigger you want and the behavior
<TabAtkins> ydaniv: the old pattern of once/repeat/alternate/state
<TabAtkins> flackr: that behavior has something that happens when the action starts and the action stops, so that's a second thing just for timeline triggers
<TabAtkins> DavidA: what's maybe not great here is we have to reinterpret bheavior in the event trigger context
<TabAtkins> flackr: i know stefan has concerns about this as well. option 3 shouldn't be contentious, it's extensible. triggersa re just event sources
<TabAtkins> DavidA: we'll have to modify the JS interface, so trigger.addAnimation(), you'll also specify the behavior
<TabAtkins> flackr: yeah, we can modify idl to match once we decide on css
<TabAtkins> ydaniv: making sure i get this right
<TabAtkins> ydaniv: with event triggers, you don't ahve behavior of start/end
<TabAtkins> s/behavior/action/
<TabAtkins> ydaniv: so for now we only allow events to play forwards
<TabAtkins> ydaniv: in option 3 we add a function that ties an event to an action, like play or reverse
<flackr> animation-trigger: trigger(--trigger-name, <action name>, behavior)
<TabAtkins> ydaniv: so how do you specify clicking to start and pause or wahtever
<TabAtkins> flackr: you add two triggers, and we specify that animation-trigger can do multiple triggers
<flackr> animation-trigger: trigger(--timeline-trigger, enter, play) trigger(--timeline-trigger, exit, pause)
<TabAtkins> DavidA: i was interpreting option 3 as, if you want multiple event associations, you don't need more than on even ttrigger
<TabAtkins> flackr: does this example make sense?
<TabAtkins> ydaniv: but the behavior alway sstarts with playing
<TabAtkins> flackr: we could default to that, yeah, but it' snot necessarily what you always want
<TabAtkins> DavidA: yeah, you might want alternate on clicking so it always inverts the playback rate
<TabAtkins> s/inverts/negates/
<ydaniv> TabAtkins: I found most useful is that the 4 actions are use most times
<ydaniv> ... we should imply a lot of things
<ydaniv> ... being able to say what a trigger does in a specific animation phase is useful
<TabAtkins> flackr: i agree. i think when we define the behavior part, we define that the behavior can depend on the current animation state
<TabAtkins> flackr: i think "play and restart" can be different from "play but do nothing if it's already playing"
<TabAtkins> flackr: similarly, "play if paused, reverse if finished"
<TabAtkins> DavidA: the "once" behavior needs to be covered too
<TabAtkins> flackr: that can also be based on animation state. "play if paused, do nothing if idle"
<TabAtkins> DavidA: doesn't this imply some state for the trigger?
<TabAtkins> flackr: no
<TabAtkins> DavidA: say you play on click, something else pauses it, then you click again. what should happen?
<TabAtkins> flackr: i think all of the state should just be animation state
<ydaniv> TabAtkins: what would that look like?
<ydaniv> ... my idea is that we imply couple of behavior keywords the imply these behaviors, but specify a particular phase
<TabAtkins> TabAtkins: have several behavior keywords that imply behaviors in each phase, but let you also specify a single phase that you're giving a behavior to. then either the trigger() can tka emultiple phase behaviors, or multiple trigger()s can be used, one for each phase
<TabAtkins> flackr: that's most general, yeah. start with all-phase behaviors, then see if per-phase is needed?
<TabAtkins> TabAtkins: when me and david explored this, we realized a bunch of keyword variants are needed
<TabAtkins> TabAtkins: but i think it's okay to start with single keywords defining all four phase behaviors, and see if it explodes and needs per-phase keywords later
<TabAtkins> DavidA: can we return to the core issue here?
<TabAtkins> flackr: yeah, i think we've come to an agreement on animation-trigger behavior
<TabAtkins> DavidA: do we want to make sure we have syntax sapce for multiple triggers on a single animation?
<TabAtkins> TabAtkins: looks like flackr's syntax is just fine for that, trigger() functions space-seaprated in animation-trigger
<TabAtkins> flackr: bikeshedding welcome on names, but yeah
<TabAtkins> ydaniv: another concern, we mentioned timelines being "1d" versus events beign "0d"
<TabAtkins> ydaniv: do we need an issue to talk about that?
<TabAtkins> flackr: for 2d stuff, i put in the proposal for a view trigger, it's 2d by default
<TabAtkins> DavidA: i think he's saying that view-trigger is another trigger type, but pointer-trigger would be yet anohter
<TabAtkins> flackr: we can define that space, maybe we can combine views and pointers
<TabAtkins> flackr: timeline trigger is a single dimension
<TabAtkins> ydaniv: we can bake that in?
<TabAtkins> DavidA: actually, thinking about intersecting multiple timeslines to make a "2d" version. works for both view and pointer
<TabAtkins> ydaniv: and sometimes you want intersection, sometimes you want "either" timeline
<TabAtkins> flackr: for timelines, I think intersection is what matters. "either" timeline is done with multiple triggers
<TabAtkins> flackr: i'm not opposed to intersection of timelines. need a specific proposal, but seems reasonable.
<TabAtkins> proposed resolution: syntax TBD, but go with option 3, where animation-trigger takes a trigger(name, behavior) function
<TabAtkins> [discussion about event type]
<TabAtkins> flackr: for timeline, there's entering and exiting, each of those have a behavior
<RRSAgent> I have made the request to generate https://www.w3.org/2025/08/20-houdini-minutes.html fantasai
<TabAtkins> ydaniv: not quite. you ahve a view tiemline and two ranges. when you enter you apply one behavior. then you range changes, when you exit.... right, you ahve another behavior
<TabAtkins> flackr: for events, like trigger(--source, click play)
<fantasai> i/Topic: [css-animations-2] Move scroll/scribenick: TabAtkins
<RRSAgent> I have made the request to generate https://www.w3.org/2025/08/20-houdini-minutes.html fantasai
<TabAtkins> TabAtkins: ah, i thought event types were listed in event-trigger-*
<TabAtkins> flackr: initially, but we're moving away from that
<TabAtkins> TabAtkins: ok, makes sense then
<TabAtkins> trigger(<dashed-ident>, [<action> <behavior>]#)
<TabAtkins> ydaniv: so timeline-trigger is still a set of properties, but event-trigger is just a single longhand then
<TabAtkins> TabAtkins: do we want to resolve on this syntax precisely?
<TabAtkins> flackr: yeah. we can review later
<TabAtkins> proposed resolution: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior
<TabAtkins> proposed resolution: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animation
<TabAtkins> RESOLVED: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animation
Later discussion with @fantasai led to some more possibility: rather than only having event sources emit naked events caught by trigger(), have them (a) also emit "higher-level" events (like activate), and (b) let authors bind one or more events to a chosen name, so you can semantically group some events together.
So:
.source {
event-trigger-name: --foo;
event-trigger-actions: --bar click press("k"), --baz press("Enter");
/* the --foo event trigger source defined two named actions, --bar and --baz. */
}
.anim {
animation: my-anim;
animation-trigger: trigger(--foo, --bar play, --baz pause, press("Escape") reset);
/* can refer to multiple trigger actions, either by "action name" or directly */
}
Later discussion with @fantasai led to some more possibility: rather than only having event sources emit naked events caught by trigger(), have them (a) also emit "higher-level" events (like activate), and (b) let authors bind one or more events to a chosen name, so you can semantically group some events together.
So:
.source {
event-trigger-name: --foo;
event-trigger-actions: --bar click press("k"), --baz press("Enter");
/* the --foo event trigger source defined two named actions, --bar and --baz. */
}
.anim {
animation: my-anim;
animation-trigger: trigger(--foo, --bar play, --baz pause, press("Escape") reset);
/* can refer to multiple trigger actions, either by "action name" or directly */
}
The resolution (and ensuing conversation) above probably belonged in #12336. The main question in that issue (to separate namespaces or not) was resolved on, so I've filed a new issue where I hope we can nail down the CSS syntax: #12652.
See #12652 (comment) for how the currently written up behaviors can be handled with a simple set of enter/exit actions which may help inform which actions we need.
The CSS Working Group just discussed [web-animations-2][css-animations-2] Set of actions for animation triggers, and agreed to the following:
RESOLVED: Accept the keywords from https://github.com/w3c/csswg-drafts/issues/12611#issuecomment-3377529486
The full IRC log of that discussion
<dbaron> fantasai, I think the second-place week in January is the week *before* MLK day
<emilio> DavidA: We started talking about this last week
<emilio> ... about keywords for animation-trigger
<emilio> ... and what actions the trigger takes on animation
<emilio> ... there's a list of keywords in the issue, I think we have agreement on the slightly reduced scope of the set of keywords
<astearns> this table? https://github.com//issues/12611#issuecomment-3377529486
<emilio> ... we want to resolve on the table in the issue
<fantasai> or this one? https://github.com//issues/12611#issuecomment-3379721618
<emilio> astearns: there's several
<bramus> The link from astearns is the correct one
<emilio> DavidA: yeah the last on my comment
<emilio> fantasai: Is it the same as crissov's comment?
<emilio> DavidA: yeah no different in semantics
<emilio> PROPOSAL: Accept the definition in the table
<flackr> +1
<bramus> +1
<kbabbitt> Seems reasonable to me
<ydaniv> +1
<emilio> astearns: objections?
<emilio> RESOLVED: Accept the keywords from https://github.com//issues/12611#issuecomment-3377529486
<emilio> flackr: I believe both tables are functionally the same
Activity
css-meeting-bot commentedon Aug 20, 2025
The Houdini Task Force just discussed
[web-animations-2][css-animations-2] Set of actions for animation triggers, and agreed to the following:RESOLVED: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animationThe full IRC log of that discussion
<TabAtkins> flackr: we've set up our triggers such that a named trigger has some set of associated actions<TabAtkins> flackr: UI events, or enter/exit for timelines
<TabAtkins> flackr: there are, i think, 3 ways to associate them with an animation behavior
<TabAtkins> flackr: 1) in trigger definition, specify this action has this behavior
<TabAtkins> flackr: 2) like ydaniv proposed, on the animating element you specify the behavior, and there's something about exit behaviors
<TabAtkins> flackr: the only way i can make this make sense is that the exit has another behavior in the animation-trigger proeprty
<TabAtkins> flackr: 3) an explicit syntax, maybe functional, in animation-trigger that links a trigger name to an animation behavior
<TabAtkins> flackr: i think third is most generic and conceptually simple
<TabAtkins> flackr: it leave sit so triggers don't mention animations
<TabAtkins> flackr: and we can do more stuff with triggers in the futre
<TabAtkins> ydaniv: in option 2 i allowed 2 triggers, was continuing the line tab and elika took
<TabAtkins> ydaniv: but if we go back to just allowing one trigger, you spec the trigger you want and the behavior
<TabAtkins> ydaniv: the old pattern of once/repeat/alternate/state
<TabAtkins> flackr: that behavior has something that happens when the action starts and the action stops, so that's a second thing just for timeline triggers
<TabAtkins> DavidA: what's maybe not great here is we have to reinterpret bheavior in the event trigger context
<TabAtkins> flackr: i know stefan has concerns about this as well. option 3 shouldn't be contentious, it's extensible. triggersa re just event sources
<TabAtkins> DavidA: we'll have to modify the JS interface, so trigger.addAnimation(), you'll also specify the behavior
<TabAtkins> flackr: yeah, we can modify idl to match once we decide on css
<TabAtkins> ydaniv: making sure i get this right
<TabAtkins> ydaniv: with event triggers, you don't ahve behavior of start/end
<TabAtkins> s/behavior/action/
<TabAtkins> ydaniv: so for now we only allow events to play forwards
<TabAtkins> ydaniv: in option 3 we add a function that ties an event to an action, like play or reverse
<flackr> animation-trigger: trigger(--trigger-name, <action name>, behavior)
<TabAtkins> ydaniv: so how do you specify clicking to start and pause or wahtever
<TabAtkins> flackr: you add two triggers, and we specify that animation-trigger can do multiple triggers
<flackr> animation-trigger: trigger(--timeline-trigger, enter, play) trigger(--timeline-trigger, exit, pause)
<TabAtkins> DavidA: i was interpreting option 3 as, if you want multiple event associations, you don't need more than on even ttrigger
<TabAtkins> flackr: does this example make sense?
<TabAtkins> ydaniv: but the behavior alway sstarts with playing
<TabAtkins> flackr: we could default to that, yeah, but it' snot necessarily what you always want
<TabAtkins> DavidA: yeah, you might want alternate on clicking so it always inverts the playback rate
<TabAtkins> s/inverts/negates/
<ydaniv> TabAtkins: I found most useful is that the 4 actions are use most times
<ydaniv> ... we should imply a lot of things
<ydaniv> ... being able to say what a trigger does in a specific animation phase is useful
<TabAtkins> flackr: i agree. i think when we define the behavior part, we define that the behavior can depend on the current animation state
<TabAtkins> flackr: i think "play and restart" can be different from "play but do nothing if it's already playing"
<TabAtkins> flackr: similarly, "play if paused, reverse if finished"
<TabAtkins> DavidA: the "once" behavior needs to be covered too
<TabAtkins> flackr: that can also be based on animation state. "play if paused, do nothing if idle"
<TabAtkins> DavidA: doesn't this imply some state for the trigger?
<TabAtkins> flackr: no
<TabAtkins> DavidA: say you play on click, something else pauses it, then you click again. what should happen?
<TabAtkins> flackr: i think all of the state should just be animation state
<ydaniv> TabAtkins: what would that look like?
<ydaniv> ... my idea is that we imply couple of behavior keywords the imply these behaviors, but specify a particular phase
<TabAtkins> TabAtkins: have several behavior keywords that imply behaviors in each phase, but let you also specify a single phase that you're giving a behavior to. then either the trigger() can tka emultiple phase behaviors, or multiple trigger()s can be used, one for each phase
<TabAtkins> flackr: that's most general, yeah. start with all-phase behaviors, then see if per-phase is needed?
<TabAtkins> TabAtkins: when me and david explored this, we realized a bunch of keyword variants are needed
<TabAtkins> TabAtkins: but i think it's okay to start with single keywords defining all four phase behaviors, and see if it explodes and needs per-phase keywords later
<TabAtkins> DavidA: can we return to the core issue here?
<TabAtkins> flackr: yeah, i think we've come to an agreement on animation-trigger behavior
<TabAtkins> DavidA: do we want to make sure we have syntax sapce for multiple triggers on a single animation?
<TabAtkins> TabAtkins: looks like flackr's syntax is just fine for that, trigger() functions space-seaprated in animation-trigger
<TabAtkins> flackr: bikeshedding welcome on names, but yeah
<TabAtkins> ydaniv: another concern, we mentioned timelines being "1d" versus events beign "0d"
<TabAtkins> ydaniv: do we need an issue to talk about that?
<TabAtkins> flackr: for 2d stuff, i put in the proposal for a view trigger, it's 2d by default
<TabAtkins> DavidA: i think he's saying that view-trigger is another trigger type, but pointer-trigger would be yet anohter
<TabAtkins> flackr: we can define that space, maybe we can combine views and pointers
<TabAtkins> flackr: timeline trigger is a single dimension
<TabAtkins> ydaniv: we can bake that in?
<TabAtkins> DavidA: actually, thinking about intersecting multiple timeslines to make a "2d" version. works for both view and pointer
<TabAtkins> ydaniv: and sometimes you want intersection, sometimes you want "either" timeline
<TabAtkins> flackr: for timelines, I think intersection is what matters. "either" timeline is done with multiple triggers
<TabAtkins> flackr: i'm not opposed to intersection of timelines. need a specific proposal, but seems reasonable.
<TabAtkins> proposed resolution: syntax TBD, but go with option 3, where animation-trigger takes a trigger(name, behavior) function
<TabAtkins> [discussion about event type]
<TabAtkins> flackr: for timeline, there's entering and exiting, each of those have a behavior
<RRSAgent> I have made the request to generate https://www.w3.org/2025/08/20-houdini-minutes.html fantasai
<TabAtkins> ydaniv: not quite. you ahve a view tiemline and two ranges. when you enter you apply one behavior. then you range changes, when you exit.... right, you ahve another behavior
<TabAtkins> flackr: for events, like trigger(--source, click play)
<fantasai> i/Topic: [css-animations-2] Move scroll/scribenick: TabAtkins
<RRSAgent> I have made the request to generate https://www.w3.org/2025/08/20-houdini-minutes.html fantasai
<TabAtkins> TabAtkins: ah, i thought event types were listed in event-trigger-*
<TabAtkins> flackr: initially, but we're moving away from that
<TabAtkins> TabAtkins: ok, makes sense then
<TabAtkins> trigger(<dashed-ident>, [<action> <behavior>]#)
<TabAtkins> ydaniv: so timeline-trigger is still a set of properties, but event-trigger is just a single longhand then
<TabAtkins> TabAtkins: do we want to resolve on this syntax precisely?
<TabAtkins> flackr: yeah. we can review later
<TabAtkins> proposed resolution: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior
<TabAtkins> proposed resolution: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animation
<TabAtkins> RESOLVED: timeline-trigger-* and event-trigger just define the source element. on the animating element, `animation-trigger: trigger()#` specifies source element, action, and behavior. (`[trigger()+ ]#` for multiple triggers on a single animation
tabatkins commentedon Aug 20, 2025
Later discussion with @fantasai led to some more possibility: rather than only having event sources emit naked events caught by trigger(), have them (a) also emit "higher-level" events (like
activate), and (b) let authors bind one or more events to a chosen name, so you can semantically group some events together.So:
fantasai commentedon Aug 20, 2025
I don't know that I agree with the last resolution.
I definitely think it's problematic to have the animating element choose what specific events it wants to bind to from the triggering element.
DavMila commentedon Aug 20, 2025
And I guess for a timeline trigger we'd have:
DavMila commentedon Aug 25, 2025
The resolution (and ensuing conversation) above probably belonged in #12336. The main question in that issue (to separate namespaces or not) was resolved on, so I've filed a new issue where I hope we can nail down the CSS syntax: #12652.
[animation-trigger] Switch IDL & CSS to action-behavior model
[animation-trigger] Switch IDL & CSS to action-behavior model
[animation-trigger] Switch IDL & CSS to action-behavior model
flackr commentedon Sep 15, 2025
See #12652 (comment) for how the currently written up behaviors can be handled with a simple set of enter/exit actions which may help inform which actions we need.
23 remaining items
css-meeting-bot commentedon Oct 8, 2025
The CSS Working Group just discussed
[web-animations-2][css-animations-2] Set of actions for animation triggers, and agreed to the following:RESOLVED: Accept the keywords from https://github.com/w3c/csswg-drafts/issues/12611#issuecomment-3377529486The full IRC log of that discussion
<dbaron> fantasai, I think the second-place week in January is the week *before* MLK day<emilio> DavidA: We started talking about this last week
<emilio> ... about keywords for animation-trigger
<emilio> ... and what actions the trigger takes on animation
<emilio> ... there's a list of keywords in the issue, I think we have agreement on the slightly reduced scope of the set of keywords
<astearns> this table? https://github.com//issues/12611#issuecomment-3377529486
<emilio> ... we want to resolve on the table in the issue
<fantasai> or this one? https://github.com//issues/12611#issuecomment-3379721618
<emilio> astearns: there's several
<bramus> The link from astearns is the correct one
<emilio> DavidA: yeah the last on my comment
<emilio> fantasai: Is it the same as crissov's comment?
<emilio> DavidA: yeah no different in semantics
<emilio> PROPOSAL: Accept the definition in the table
<flackr> +1
<bramus> +1
<kbabbitt> Seems reasonable to me
<ydaniv> +1
<emilio> astearns: objections?
<emilio> RESOLVED: Accept the keywords from https://github.com//issues/12611#issuecomment-3377529486
<emilio> flackr: I believe both tables are functionally the same
[animation-trigger] Switch IDL & CSS to action-behavior model
[css-animations-2] Add play-once animation-action #12611
[animation-trigger] Remove play-alternate and play-pause actions
[animation-trigger] Remove play-alternate and play-pause actions
[animation-trigger] Remove play-alternate and play-pause actions
Bug 2012524 [wpt PR 57337] - [animation-trigger] Remove play-alternat…