-
Notifications
You must be signed in to change notification settings - Fork 724
[css-animations-2] [web-animations-2] Animation trigger event #12314
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
base: main
Are you sure you want to change the base?
[css-animations-2] [web-animations-2] Animation trigger event #12314
Conversation
…-chromium/csswg-drafts into animation-trigger-event
…tion-trigger-event
@flackr PTAL |
@@ -770,6 +770,8 @@ for an [=animation trigger=] that enters its [=animation trigger/active interval | |||
|
|||
The behavior of each value is defined in [[web-animations-2#trigger-behaviors]]. | |||
|
|||
Issue: Should 'animation-trigger-behavior' allow multiple values (currently it does)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I don't think it does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '#' in the syntax description from line 734 means it accepts a comma-separated list of behaviors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I think that has to do with the fact that multiple animations can be specified in a comma-separated list. Each animation will then be mapped 1:1 with a comma-separated list of triggers. Each trigger still only gets one behavior. Though idk if this has been incorrectly represented in the spec text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, what @DavMila said is correct. I think this is called a coordinated list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it; I will update the PR...
|
||
<dt>''animation-trigger-type/repeat''</dt> | ||
<dd>First, if [=play state=] is [=play state/running=] or [=play state/paused=] | ||
perform the actions specified for the {{Animation/cancel}} function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More of an FYI comment perhaps: I don't yet know if this is going to be different for event-based triggers but for scroll-triggered what we want isn't cancel() but more of a "reset"... which is not yet a concept defined in the web animations spec. Essentially, it does
animation.currentTime = 0;
animation.pause();
Since you follow up by playing the animation, maybe this doesn't matter so much, but for CSS animations, cancel() will be accompanied by an animationcancel
event which we might not want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an interesting question about whether it's desirable to issue events for these transitions. They are not otherwise directly observable; is that a good thing? bad thing? Indifferent?
web-animations-2/Overview.bs
Outdated
|
||
An [=animation trigger=] |trigger| | ||
<dt>''animation-trigger-type/alternate''</dt> | ||
<dd>Perform the actions specified for the {{Animation/reverse}} function.</dd> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we reverse the animation on the first event? Is that intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great point! I need to think about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated to specify that if play state is idle then the effect is play()
, otherwise the effect is reverse()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@szager-chromium thanks for starting this, but I think we still have very active spec work on AnimationTriggers currently tracked in #12119 that may affect the current spec substantially.
I gave my comments, so far mostly things regarding the API and logic of the declarative syntax and the model of event-based triggering, before diving in to the rest.
type of an animation trigger is deduced from its attributes: a | ||
timeline-based animation trigger will have a non-empty {{AnimationTrigger/timeline}} | ||
attribute, while an event-based animation trigger will have non-empty | ||
{{AnimationTrigger/eventTarget}} and {{AnimationTrigger/eventType}} attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although we allow 2 types of animations, time-based and progress-based, using the animation
property, we don't deduce that based on empty properties. On the contrary, we have auto
initial values for all properties that are not needed when you use that type or the other.
So, IMHO we can't really add more properties to the API and expect those to be empty, both technically and design-wise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if your concern is with the WAAPI interface or the CSS syntax, but the attributes on a WAAPI object can be undef
or null
. Is it maybe the word empty
that you object to?
In the rest of the WAAPI proposal I added safeguards to ensure that an instance of AnimationTrigger
will conform to the requirement:
!(trigger.eventType ^ trigger.eventTarget) && (trigger.timeline ^ trigger.eventTarget))
... so the trigger type is detectable based on these attributes.
When a [=animation trigger/qualifying event=] is dispatched, the associated | ||
animation's playback is modified as follows, | ||
based on the trigger's {{AnimationTrigger/behavior}} | ||
and the current [=play state=] of the animation: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's correct to specify behaviors based on the type of the trigger. I think we should be specifying how each time handles its internal state and apply its specified behavior, rather than how the behavior acts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Respectfully, I disagree. Events are fundamentally ephemeral occurences, and I think it's more intuitive to express event-based triggers in terms of taking an action in response to an event without introducing the complexity of additional state, most of which is internal and thus not directly detectable. Conceptually, event-based triggers are like event handlers.
|
||
<dl> | ||
<dt>''animation-trigger-type/once''</dt> | ||
<dd>If [=play state=] is [=play state/finished=], do nothing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way it's not really a once
behavior. It will re-play as long as it's not finished.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the animation is idle
, then this will play it.
If it's running
, then this will have no effect.
If it's paused
this will un-pause it.
If it's finished
, we do nothing.
That's the intended behavior, is there something unintuitive?
Changes to animation playback occur when the associated [=timeline=] transitions | ||
between inside and outside the [=animation attachment range|attachment range=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not so accurate in spec technical terms. The timeline doesn't transition, rather its progress goes in and out of its active interval
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand your objection. The spec specifies when the trigger state is updated, and at that time if it's detected that the new state will be different from the previous state, then that can be considered a "transition". It's maybe a synthetic concept, but it's rigorous in terms of the current spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a related note: the existing spec needs some clarification over when the trigger behaviors are applied -- specifically, they should only be applied when a transition occurs.
For example, consider this description of `alternate':
"If state is primary and did trigger is true, the effect is to reverse the associated animation."
If this logic is applied on every animation update, then the animation would be reversed on every frame. The intention is clearly that this behavior should be applied only when a transition occurs, but the spec doesn't say that.
|
||
<pre class='propdef'> | ||
Name: animation-trigger | ||
Value: <<single-animation-trigger>># | ||
Value: auto | none | <<single-animation-trigger>># |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far we intentionally didn't have a none
nor auto
values for the animation-trigger
property, though this may change depending on what we resolve in #12119
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, probably if we do allow auto
/none
they should be part of the <single-animation-trigger>
def and be allowed per trigger defintion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I misunderstood before how coordinated lists were being used; I will fix this.
@@ -984,7 +1038,9 @@ Animation Type: not animatable | |||
</pre> | |||
|
|||
<pre class=prod> | |||
<dfn><single-animation-trigger></dfn> = <<single-animation-trigger-behavior>> || [ none | auto | [ [ <<dashed-ident>> | <<scroll()>> | <<view()>> ] [ normal | <<length-percentage>> | <<timeline-range-name>> <<length-percentage>>? ]{0,4} ] ] | |||
<dfn><single-animation-trigger></dfn> = [ <<single-animation-trigger-behavior>> | [ <<single-trigger-event>> | <<single-timeline-trigger>> ] ] <<single-animation-trigger-behavior>>? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow the logic here. Perhaps you meant to allow auto
and none
as possible alternatives and that's what got the syntax confusing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also me not understanding coordinated lists; will fix.
<dfn><single-animation-trigger></dfn> = <<single-animation-trigger-behavior>> || [ none | auto | [ [ <<dashed-ident>> | <<scroll()>> | <<view()>> ] [ normal | <<length-percentage>> | <<timeline-range-name>> <<length-percentage>>? ]{0,4} ] ] | ||
<dfn><single-animation-trigger></dfn> = [ <<single-animation-trigger-behavior>> | [ <<single-trigger-event>> | <<single-timeline-trigger>> ] ] <<single-animation-trigger-behavior>>? | ||
|
||
<dfn><single-timeline-trigger></dfn> = [ <<dashed-ident>> | <<scroll()>> | <<view()>> ] [ normal | <<length-percentage>> | <<timeline-range-name>> <<length-percentage>>? ]{0,4} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You changed the syntax of timeline here. timeline
also accepts none
and auto
which you removed here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also coordinated lists; will fix.
@@ -962,18 +964,70 @@ The values of 'animation-trigger-exit-range-start' have the following meaning: | |||
it defaults to 100%. | |||
</dl> | |||
|
|||
## The 'animation-trigger-name' property ## {#animation-trigger-name} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this property is not a longhand sub-property of animation-trigger
then IMO it should not be named using the scheme of animation-trigger-*
. IIUC you meant to define this property as the event source declaration, am I right?
In that case, this raises some questions:
- Is that declaration tree scoped?
- Is the name reused for all event types that are emitted from this target?
- Does containment properties affect its scope?
- Can we lift this scope, same as the
timeline-scope
property does? - Do names collide and override eachother? Or can they be used multiple times?
- Will these names be ever used only for the purpose (and scope) of animations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussion with @flackr and @DavMila, I think the plan is to use a scoping mechanism similar to anchor positioning -- specifically, there will be a trigger-scope
property to apply tree scoping, but in the absense of any applicable trigger-scope
the scope will be global. As with anchor positioning, containment will not affect scope.
The name is only used to specify the event target; the event type is specified via animation-trigger-event
or the animation-trigger
shorthand.
I will change the property to trigger-name
, to avoid confusion with the properties that can be set via animation-trigger
shorthand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I still think that the type should be part of the event declaration on the target.
Is there a specific reason you want to put the type on the animation target? IMHO, from design perspective this seems to belong on the event target.
The 'animation-trigger-name' property associates an element with | ||
all elements having an 'animation-trigger-event' property with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's not accurate to say we "associate elements". The event needs to be associated with a target, and the target here is an animation(s).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite follow you here, but I will point out firstly that the term "target" appears to be overloaded here. Because we're working with events, and "event target" is a very well-understood concept, I'm using the term "target" to refer to the event target and not the element that will animate.
There is definitely an "association" happening here:
#event-target {
trigger-name: --my-trigger;
}
#some-other-event-target {
trigger-name: --my-trigger;
}
#animatable {
animation-trigger-name: --my-trigger;
animation-trigger-event: click;
}
#some-other-animatable {
animation-trigger-name: --my-trigger;
animation-trigger-event: keydown;
}
If a click
is dispatched to either #event-target or #some-other-event-target, then #animatable will run its animations. If a keydown
is disaptched to either #event-target or #some-other-event-target, #some-other-animatable will run its animations.
Is there some other term besides "association" that better describes the relationships between these elements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we have 2 elements in play here, I was trying to use "source" for the event target, and "target" for the animated element, but let's stick with event target.
I understand the association, we definitely need that mechanism.
I'm saying we associate the event target with an animation, and not really with another element. The animation is associated with its own target, which can be nulled or changed.
The 'animation-trigger-event' property is used to specify the criteria | ||
for [=qualifying events=] that cause an [=event-based animation trigger=] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be the other way around? As in, the event source should declare the types that emit its name, and the event targets should register to the name alone?
This is normally how you would register an event. You add a handler per type, and then these handlers can publish the name to trigger behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give an example of the syntax you have in mind? It's not clear to me how to express the following using your suggestion:
#event-target {
trigger-name: --my-trigger;
}
#some-other-event-target {
trigger-name: --my-trigger;
}
#animatable {
animation-trigger-name: --my-trigger;
animation-trigger-event: click;
}
#some-other-animatable {
animation-trigger-name: --my-trigger;
animation-trigger-event: keydown;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, this example is rather confusing to me. Did you intentionally used an example with two identical names? Are they supposed to collide? Or to be aggregated?
So to simplify with 2 different names, I was thinking on something like:
#event-target {
trigger-event: --my-trigger click;
}
#some-other-event-target {
trigger-event: --my-other-trigger keydown;
}
#animatable {
animation-trigger: repeat event(--my-other-trigger);
}
#some-other-animatable {
animation-trigger: --my-other-trigger;
}
Specification for event-based animation triggers, as discused in issue##12029