1. Delta specification
This is a delta specification, meaning that it currently contains only the differences from CSS Animations Level 1 [CSS3-ANIMATIONS]. Once the Level 1 specification is closer to complete, it will be merged with the additions here into a complete level 2 specification.
2. Introduction
Append: This specification builds on the animation model defined in Web Animations [WEB-ANIMATIONS].
3. Animations
This section is not written as a delta spec. It imports the corresponding text from CSS Animations Level 1 [CSS3-ANIMATIONS] but removes text where the behavior is defined by Web Animations.
CSS Animations generates animation objects. The animation start time is the time at which the style applying the animation and the corresponding @keyframes rule are both resolved. f an animation is specified for an element but the corresponding keyframes rule does not yet exist, the animation cannot start; the animation will start from the beginning as soon as a matching @keyframes rule can be resolved. An animation specified by dynamically modifying the element’s style will start when this style is resolved; that may be immediately in the case of a pseudo style rule such as hover, or may be when the scripting engine returns control to the browser (in the case of style applied by script). Note that dynamically updating keyframe style rules does not start or restart an animation.
Note, that so long as there is no matching @keyframes rule it is unobservable whether a user agent generates an animation and assigns it an unresolved start time or simply defers creating an animation altogether since there is no API that returns idle animations. Either implementation is acceptable.
An animation applies to an element if its name appears as one of the identifiers in the computed value of the animation-name property and the animation uses a valid @keyframes rule. Once an animation has started it continues until it ends or the animation-name is removed. Changing the values of animation properties updates the properties of any running animations.
Note also that changing the value of animation-name does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation using only CSS markup, it must be removed then reapplied.
div { animation-name: diagonal-slide; animation-duration: 5s; animation-iteration-count: 10; } @keyframes diagonal-slide { from { left: 0; top: 0; } to { left: 100px; top: 100px; } }
This will produce an animation that moves an element from (0, 0) to (100px, 100px) over five seconds and repeats itself nine times (for a total of ten iterations).
Setting the display property to none will cancel any running animation applied to the element and its descendants. If an element has a display of none, updating display to a value other than none will cause all animations applied to the element by the animation-name property to be recreated, as well as all animations applied to descendants with display other than none.
While authors can use animations to create dynamically changing content, dynamically changing content can lead to seizures in some users. For information on how to avoid content that can lead to seizures, see Guideline 2.3: Seizures: Do not design content in a way that is known to cause seizures ([WCAG20]).
Implementations may ignore animations when the rendering medium is not interactive e.g. when printed. A future version of this specification may define how to render animations for these media.
4. Keyframes
4.1. The animation-name property
Need to add something like this: https://lists.w3.org/Archives/Public/www-style/2015Jul/0391.html.
4.2. The animation-play-state property
4.2.1. Interaction between animation-play-state and the Web Animations API
Both this specification and the Web Animations specification [WEB-ANIMATIONS]
define mechanisms for pause control, specifically the animation-play-state
property, and the play()
and pause()
methods
respectively.
The interaction of these methods can be summarized as follows:
-
Calling
pause()
is sticky. The animation will remain paused until there is a subsequent call toplay()
after which point the animation will begin tracking changes to the computed value of the animation-play-state property on the owning element from the next moment it becomes newly paused. -
In the computed animation-play-state on the owning element is paused, calling
play()
will temporarily override the animation-play-state until it next becomes running.
With regards to the pausing, an animation can be considered to be in one of five mutually-exclusive states:
- Running
- Running and temporarily overriding animation-play-state: paused
- Paused and sticky overriding animation-play-state: running
- Paused and sticky overriding animation-play-state: paused
- Paused by animation-play-state
A state transition chart follows:
Initial state | ||||||
---|---|---|---|---|---|---|
Event | A | B | C | D | E | |
Resulting state | play()
| A | B | A | B | B |
pause()
| C | D | C | D | D | |
animation-play-state → running | A | A | C | C | A | |
animation-play-state → paused | E | B | D | D | E |
Need to define the difference between setting animation-play-state to
running and calling play()
. Specifically, the former
follows the same procedure to play an animation but does not
perform the snapping behavior that results from comparing the current
time to zero or the target effect end. This probably requires
rearranging the algorithm in Web Animations to take an extra argument to opt-out
of this behavior.
4.3. The animation-composition property
The animation-composition property defines the composite operation used when multiple animations affect the same property simultaneously.
Name: | animation-composition |
---|---|
Value: | <single-animation-composition># |
Initial: | replace |
Applies to: | all elements, ::before and ::after pseudo-elements |
Inherited: | none |
Percentages: | N/A |
Media: | interactive |
Computed value: | As specified |
Animatable: | no |
Canonical order: | per grammar |
<single-animation-composition> = replace | add | accumulate
The values of animation-composition have the meaning defined for the corresponding values values of the composite operation defined in Web Animations [WEB-ANIMATIONS].
When specified in a keyframe, animation-composition defines the operation used for each property specified in that keyframe until the next keyframe specifying each property.
@keyframes heartbeat { from { scale: 1; animation-timing-function: ease-out; } 30% { scale: 1.3; } } .heartbeat { animation: heartbeat 0.3s 2s infinite; } @keyframes throb { 50% { scale: 1.8; } } .icon:mouseover { animation: throb 0.4s add; }
If these two animations are applied to the same element, normally only one animation would apply, but by specifying add as the animation-composition on the second animation, the result of the two animations will be combined.
Since CSS Transitions [CSS3-TRANSITIONS] have a lower composite order, it is possible to use animation-composition to combine CSS Animations with underlying transitions as in the following example.
.icon { filter: blur(20px); transition: filter 0.5s; } .icon:hover { filter: blur(0px); animation: brightness-pulse 3s infinite add; } @keyframes pulse { 0% { scale: 1.1; filter: brightness(130%); } 10% { scale: 1; filter: brightness(100%); } }
Create pictures of these examples and verify they make sense.
4.4. Owning element
The owning element of a CSS Animation refers to the element or pseudo-element to which the animation-name property was applied that generated the animation.
If an animation was generated directly by script (e.g. using
the CSSAnimation()
constructor) then it has no owning element.
If an animation generated using the markup defined in this specification is later disassociated from that markup by an update to the computed value of the animation-name property on the owning element, the animation is dissasociated from its owning element (that is, it has no owning element from that point forwards).
In the example below, animation
initially has an owning
element but the association is broken through an update to the
computed value of elem
’s animation-name property.
elem.style.animation = 'spin 1s'; let animation = elem.getAnimations()[0]; // |animation|'s owning element is elem elem.style.animation = ''; // |animation| no longer has an owning element
Note that although the owning element is often equal to the target element of an animation’s target effect, this is not always the case. The following example demonstrates some of the situations where these two elements may differ.
elem.style.animation = 'move 1s'; let animation = elem.getAnimations()[0]; // animation.effect.target == elem == animation’s owning element let mutableEffect = animation.effect.clone(); animation.effect = mutableEffect; animation.effect.target = elem2; // animation.effect.target == elem2 != animation’s owning element animation.effect = null; // animation.effect.target is undefined != animation’s owning element
4.5. Animation composite order
Animations generated from the markup and
interfaces (e.g. the CSSAnimation()
constructor) defined in this
specification have an animation type of ‘CSS Animation’.
CSS Animations with an owning element have a later composite order than CSS Transitions but an earlier composite order than animations without a specific animation type.
Within the set of CSS Animations with an owning element, two animations A and B are sorted in composite order (first to last) as follows:
-
If the owning element of A and B differs, sort A and B by tree order of their corresponding owning elements. With regard to pseudo-elements, the sort order is as follows:
-
element
-
::before
-
::after
-
element children
-
-
Otherwise, sort A and B based on their position in the computed value of the animation-name property of the (common) owning element.
The composite order of CSS Animations without an owning element is based on their position in the global animation list.
CSS Animations generated using the markup defined in this specification are not added to the global animation list when they are created. Instead, these animations are appended to the global animation list at the first moment when they transition out of the idle play state after being disassociated from their owning element. CSS Animations that have been disassociated from their owning element but are still idle do not have a defined composite order.
Note, this behavior relies on the fact that disassociating an animation from its owning element always causes it to enter (or remain) in the idle play state.
CSS Animations created using the CSSAnimation()
constructor are appended
to the global animation list at the moment they are constructed.
Would it be more consistent to append them at the moment they first
transition out of idle? (Just for animations created using CSSAnimation()
,
not for generic Animation
objects.)
5. Animation events
5.1. Types of AnimationEvent
The additional types of animation events that can occur are:
- animationcancel
-
The animationcancel event occurs when the animation stops
running in a way that does not fire an animationend event, such
as a change in the animation-name that removes the animation, or the
animating element or one of its ancestors becoming display:none.
- Bubbles: Yes
- Cancelable: No
- Context Info: animationName, elapsedTime, pseudoElement
5.2. Event dispatch
Note, this is a more general description of event dispatch than that of CSS Animations Level 1 [CSS3-ANIMATIONS] since it must account for the possibility of animations being seeked using the Web Animations API [WEB-ANIMATIONS].
For the purpose of determining which events to dispatch, an animation can be considered to be in one of four mutually-exclusive event states determined using the following procedure:
-
If the animation is idle or has no target effect it is idle.
-
Otherwise, if the animation has a current time less than the start delay of its target effect, or, if the animation’s playback rate is less than zero and it has a current time less than or equal to the start delay of its target effect, it is left-active.
-
Otherwise, if the animation has a current time greater than its target effect end, or, if the animation’s playback rate is greater than or equal to zero and it has a current time greater than or equal to its target effect end, it is right-active.
Each time the animation is sampled, the events to dispatch are determined by comparing the event state before and after the sample as follows:
-
animationstart
-
-
animationstart, animationend
-
-
animationend
-
animationiteration if there has been a change to the animation’s target effect’s current iteration
-
animationcancel
6. DOM interfaces
6.1. The CSSAnimation interface
[Constructor(DOMString animationName)] interface CSSAnimation : Animation { readonly attribute DOMString animationName; };
-
Creates a new
CSSAnimation
object.The target effect of the newly-created object is a
KeyframeEffectReadOnly
object created using the procedure defined in §4.1 The animation-name property and using the active document as the context document. The createdKeyframeEffectReadOnly
object continues to track changes to keyframes rules so long as it is attached to this object.It is not clear what the most reasonable behavior is here regarding liveness. Could we make the generated object always track changes? That would suggest a special sub-type of
KeyframeEffectReadOnly
that tracks its context document and animationName. Alternatively we could make it a one-shot thing that creates aKeyframeEffect
object. -
animationName, of type DOMString, readonly
-
The key used to find matching keyframes rules that define target effect at the point when the animation was created. This is the value of the animation-name property that caused this object to be generated or, if this object was generated using the programming interface, the
animationName
argument that was passed to theCSSAnimation()
constructor.
6.2. Requirements on pending style changes
Various operations may affect the computed values of properties on elements. User agents may, as an optimization, defer recomputing these values until it becomes necessary. However, all operations included in programming interface defined in this specification, as well as those operations defined in Web Animations [WEB-ANIMATIONS] that may return objects defined by this specification, must produce a result consistent with having fully processed any such pending changes to computed values.
elem
is initially updated, a user agent may defer recalculating
the computed value of the animation property.
However, the getAnimations
method from the Element
interface
which is specified by [WEB-ANIMATIONS] can return CSSAnimation
objects as
defined in this specification, and hence the user agent must calculate the
updated value elem
’s animation property and create
the requested CSSAnimation
object before returning its result.
elem.style.animation = 'fadeOut 1s'; elem.getAnimations()[0].pause();