Description | Defines and runs animations. |
Required Script | <script async custom-element="amp-animation" src="https://cdn.ampproject.org/v0/amp-animation-0.1.js"></script> |
Supported Layouts | nodisplay |
Examples | animations.amp.html |
- Overview
- Format
- Triggering animation
- on actions
Overview
AMP Animations rely on Web Animations API to define and run animations in AMP documents.
Format
An amp-animation
element defines such an animation as a JSON structure.
Top-level animation specification
The top-level object defines an overall animation process which consists of an arbitrary number of animation components
defined as an animations
array:
<amp-animation layout="nodisplay"> <script type="application/json"> { // Timing properties ... "animations": [ { // Animation 1 }, ... { // Animation N } ] } </script> </amp-animation>
Placement in DOM
<amp-animation>
is only allowed to be placed as a direct child of <body>
element if trigger="visibility"
. If trigger
is not specified and animation's playback is controlled programmatically via its actions, it can be placed anywhere in the DOM.
Animation component
Each animation component is a keyframes effect and is comprised of:
- Target element(s) referenced by a selector
- Conditions: media query and supports condition
- Timing properties
- Keyframes
{ "selector": "#target-id", // Conditions // Variables // Timing properties // Subtargets ... "keyframes": [] }
Conditions
Conditions can specify whether this animation component is included in the final animation.
Media query
Media query can be specified using the media
property. This property can contain any expression allowed
for Window.matchMedia API and corresponds to @media
CSS rule.
If value is specified for an animation component, the animation component will only be included if the media query will match the current environment.
Supports condition
Supports condition can be specified using the supports
property. This property can contain any expression allowed
for CSS.supports API and corresponds to @supports
CSS rule.
If value is specified for an animation component, the animation component will only be included if the supports condition will match the current environment.
Animation switch
statement
In some cases it's convenient to combine multiple conditional animations with an optional default into a single animation. This can be done using switch
animation statement in this format:
{ // Optional selector, vars, timing ... "switch": [ { "media": "(min-width: 320px)", "keyframes": {...}, }, { "supports": "offset-distance: 0", "keyframes": {...}, }, { // Optional default: no conditionals } ] }
In switch
animation, the candidates are evaluated in the defined order and the first animation that matches conditional statements is executed and the rest are ignored.
For instance, this animation runs motion-path animation if supported and falls back to transform:
{ "selector": "#target1", "duration": "1s", "switch": [ { "supports": "offset-distance: 0", "keyframes": { "offsetDistance": [0, '300px'] } }, { "keyframes": { "transform": [0, '300px'] } } ] }
Variables
An animation component can declare CSS variables that will be used for timing and keyframes values via var()
expressions. var()
expressions are evaluated using the current target context. The CSS variables specified in animation components are propagated to nested animations, applied to animation targets and thus override CSS variables used in final animations.
For instance:
<amp-animation layout="nodisplay"> <script type="application/json"> { "--delay": "0.5s", "--x": "100px", "animations": [ { "selector": "#target1", "delay": "var(--delay)", "--x": "150px", "keyframes": {"transform": "translate(var(--x), var(--y, 0px)"} }, ... ] } </script> </amp-animation>
In this sample:
--delay
is propagated into nested animations and used as a delay of#target1
animation.--x
is propagated into nested animations but overriden by the#target1
animation and later used fortransform
property.--y
is not specified anywhere in the<amp-animation>
and thus will be queried on the#target1
element. It defaults to0px
if not defined in CSS either.
For more information on var()
, see the var()
and calc()
section.
Timing properties
Top-level animation and animation components may contain timing properties. These properties are defined in detail in the AnimationEffectTimingProperties of the Web Animation spec. The set of properties allowed here includes:
Property | Type | Default | Description |
---|---|---|---|
duration |
time | 0 | The animation duration. Either a numeric value in milliseconds or a CSS time value, e.g. `2s`. |
delay |
time | 0 | The delay before animation starts executing. Either a numeric value in milliseconds or a CSS time value, e.g. `2s`. |
endDelay |
time | 0 | The delay after the animation completes and before it's actually considered to be complete. Either a numeric value in milliseconds or a CSS time value, e.g. `2s`. |
iterations |
number or "Infinity" or "infinite" |
1 | The number of times the animation effect repeats. |
iterationStart |
number/CSS | 0 | The time offset at which the effect begins animating. |
easing |
string | "linear" | The timing function used to scale the time to produce easing effects. |
direction |
string | "normal" | One of "normal", "reverse", "alternate" or "alternate-reverse". |
fill |
string | "none" | One of "none", "forwards", "backwards", "both", "auto". |
All timing properties allow either a direct numeric/string values or CSS values. For instance, "duration" can be specified as 1000
or 1s
or 1000ms
. In addition, calc()
and var()
and other CSS expressions are also allowed.
An example of timing properties in JSON:
{ ... "duration": "1s", "delay": 100, "endDelay": "var(--end-delay, 10ms)", "easing": "ease-in", "fill": "both" ... }
Animation components inherit timing properties specified for the top-level animation.
Subtargets
Everywhere where selector
can be specified, it's possible to also specify subtargets: []
. Subtargets can override timing properties or variables defined in the animation for specific subtargets indicated via either an index or a CSS selector.
For instance:
{ "selector": ".target", "delay": 100, "--y": "100px", "subtargets": [ { "index": 0, "delay": 200, }, { "selector": ":nth-child(2n+1)", "--y": "200px" } ] }
In this example, by default all targets matched by the ".target" have delay of 100ms and "--y" of 100px. However, the first target (index: 0
) is overriden to have delay of 200ms; and odd targets are overriden to have "--y" of 200px.
Notice, that multiple subtargets can match one target element.
Keyframes
Keyframes can be specified in numerous ways described in the keyframes section of the Web Animations spec or as a string refering to the @keyframes
name in the CSS.
Some typical examples of keyframes definitions are below.
Shorthand object-form "to" format specifies the final state at 100%:
{ "keyframes": {"opacity": 0, "transform": "scale(2)"} }
Shorthand object-form "from-to" format specifies the starting and final states at 0 and 100%:
{ "keyframes": { "opacity": [1, 0], "transform": ["scale(1)", "scale(2)"] } }
Shorthand object-form "value-array" format specifies multiple values for starting, final states and multiple (equal-spaced) offsets:
{ "keyframes": { "opacity": [1, 0.1, 0], "transform": ["scale(1)", "scale(1.1)", "scale(2)"] } }
The array-form specifies keyframes. Offsets are assigned automatically at 0, 100% and spaced evenly in-between:
{ "keyframes": [ {"opacity": 1, "transform": "scale(1)"}, {"opacity": 0, "transform": "scale(2)"} ] }
The array-form can also include "offset" explicitly:
{ "keyframes": [ {"opacity": 1, "transform": "scale(1)"}, {"offset": 0.1, "opacity": 0.1, "transform": "scale(2)"}, {"opacity": 0, "transform": "scale(3)"} ] }
The array-form can also include "easing":
{ "keyframes": [ {"easing": "ease-out", "opacity": 1, "transform": "scale(1)"}, {"opacity": 0, "transform": "scale(2)"} ] }
For additional keyframes formats refer to Web Animations spec.
The property values allow any valid CSS values, including calc()
, var()
and other CSS expressions.
Keyframes from CSS
Another way to specify keyframes is in the document's stylesheet (<style>
tag) as @keyframes
CSS rule. For instance:
<style amp-custom> @keyframes keyframes1 { from { opacity: 0; } to { opacity: 1; } } </style> <amp-animation layout="nodisplay"> <script type="application/json"> { "duration": "1s", "keyframes": "keyframes1" } </script> </amp-animation>
CSS @keyframes
are mostly equivalent to inlining keyframes definition in the JSON per Web Animations spec. However, there are some nuances:
- For broad-platform support, vendor prefixes, e.g.
@-ms-keyframes {}
or-moz-transform
may be needed. Vendor prefixes are not needed and not allowed in the JSON format, but in CSS they could be necessary. - Platforms that do not support
calc()
andvar()
will not be able to take advantage ofamp-animation
polyfills when keyframes are specified in CSS. It's thus recommended to always include fallback values in CSS. - CSS extensions such as
width()
,height()
,num()
,rand()
,index()
andlength()
cannot be used in CSS.
White listed properties for keyframes
Not all CSS properties can be used in keyframes. Only CSS properties that modern browsers can optimize and animate quickly are white listed. This list will grow as more properties are confirmed to provide good performance. Currently the list contains:
Notice that the use of vendor prefixed CSS properties is neither needed nor allowed.
Abbreviated forms of animation configuration
If the animation only involves a single element and a single keyframes effect is sufficient, the configuration can be reduced to this one animation component only. For instance:
<amp-animation layout="nodisplay"> <script type="application/json"> { "selector": "#target-id", "duration": "1s", "keyframes": {"opacity": 1} } </script> </amp-animation>
If the animation is comprised of a list of components, but doesn't have top-level animation, the configuration can be reduced to an array of components. For instance:
<amp-animation layout="nodisplay"> <script type="application/json"> [ { "selector": ".target-class", "duration": 1000, "keyframes": {"opacity": 1} }, { "selector": ".target-class", "duration": 600, "delay": 400, "keyframes": {"transform": "scale(2)"} } ] </script> </amp-animation>
Animation composition
Animations can reference other animations thus combining several amp-animation
declarations into a single final animation. Referencing an animation from another animation is mostly the same as nesting. The reason why one would want to split animations into different elements would be to reuse the same animation from several places or to simply make each animation declaration smaller and more manageable.
For instance:
<amp-animation id="anim1" layout="nodisplay"> <script type="application/json"> { "animation": "anim2", "duration": 1000, "--scale": 2 } </script> </amp-animation> <amp-animation id="anim2" layout="nodisplay"> <script type="application/json"> { "selector": ".target-class", "keyframes": {"transform": "scale(var(--scale))"} } </script> </amp-animation>
This sample animation, will combine "anim2" animation as part of "anim1". The "anim2" is included
without a target (selector
). In such case, the included animation is expected to reference its own target.
Another form allows the including animation to provide the target or multiple targets. In that case, the included animation is executed for each matched target. For instance:
<amp-animation id="anim1" layout="nodisplay"> <script type="application/json"> { "selector": ".target-class", "animation": "anim2", "duration": 1000, "--scale": 2 } </script> </amp-animation> <amp-animation id="anim2" layout="nodisplay"> <script type="application/json"> { "keyframes": {"transform": "scale(var(--scale))"} } </script> </amp-animation>
Here, whether the ".target-class" matches one element, several or none - the "anim2" is executed for each matched target.
The variables and timing properties specified in the caller animation are passed to the included animation as well.
var()
and calc()
expressions
amp-animation
allows use of var()
and calc()
expressions for timing and keyframes values.
For instance:
<amp-animation layout="nodisplay"> <script type="application/json"> [ { "selector": ".target-class", "duration": "4s", "delay": "var(--delay)", "--y": "var(--other-y, 100px)", "keyframes": {"transform": "translate(calc(100vh + 20px), var(--y))"} } ] </script> </amp-animation>
Both var()
and calc()
polyfilled on platforms that do not directly support them. var()
properties are extracted from the corresponding target elements. However, it's unfortunately impossible to fully polyfill var()
. Thus, where compatibility is important, it's strongly recommended to include default values in the var()
expressions. For instance:
<amp-animation layout="nodisplay"> <script type="application/json"> [ { "selector": ".target-class", "duration": "4s", "delay": "var(--delay, 100ms)", } ] </script> </amp-animation>
Animation components can specify their own variables as --var-name
fields. These variables are propagated into nested animations and override variables of target elements specified via stylesheet (<style>
tag). var()
expressions first try to resolve variable values specified in the animations and then by querying target styles.
CSS extensions
amp-animation
provides several CSS extensions for typical animations needs: rand()
, num()
, width()
, and height()
. These functions can be used everywhere where CSS values can be used within amp-animation
, including timing and keyframes values.
CSS index()
extension
The index()
function returns an index of the current target element in the animation effect. This is most relevant when multiple targets are animated with the same effect using selector
property. The first target matched by the selector will have index 0
, the second will have index 1
and so on.
Among other things, this property can be combined with calc()
expressions and be used to create staggered effect. For instance:
{ "selector": ".class-x", "delay": "calc(200ms * index())" }
CSS length()
extension
The length()
function returns the number of target elements in the animation effect. This is most relevant when combined with index()
:
{ "selector": ".class-x", "delay": "calc(200ms * (length() - index()))" }
CSS rand()
extension
The rand()
function returns a random CSS value. There are two forms.
The form without arguments simply returns the random number between 0 and 1.
{ "delay": "calc(10s * rand())" }
The second form has two arguments and returns the random value between these two arguments.
{ "delay": "rand(5s, 10s)" }
CSS width()
and height()
extensions
The width()
and height()
extensions return the width/height of the animated element or the element specified by the selector. The returned value is in pixels, e.g. 100px
.
The following forms are supported:
width()
andheight()
- width/height of the animated element.width('.selector')
andheight('.selector')
- width/height of the element specified by the selector. Any CSS selector can be used. For instance,width('#container > li')
.width(closest('.selector'))
andheight(closest('.selector'))
- width/height of the element specified by the closest selector.
The width()
and height()
are epsecially useful for transforms. The left
, top
and similar CSS properties that can use %
values to express animations proportional to container size. However, transform
property interpretes %
values differently - as a percent of the selected element. Thus, the width()
and height()
can be used to express transform animations in terms of container elements and similar.
These functions can be combined with calc()
, var()
and other CSS expressions. For instance:
{ "transform": "translateX(calc(width('#container') + 10px))" }
CSS num()
extension
The num()
function returns a number representation of a CSS value. For instance:
num(11px)
yields11
;num(110ms)
yields110
;- etc.
For instance, the following expression calculates the delay in seconds proportional to the element's width:
{ "delay": "calc(1s * num(width()) / 100)" }
SVG animations
SVGs are awesome and we certainly recommend their use for animations!
SVG animations are supported via the same CSS properties described in White listed properties for keyframes with some nuances:
- IE/Edge SVG elements do not support CSS
transform
properties. Thetransform
animation itself is polyfilled. However, initial state defined in a stylesheet is not applied. If the initial transformed state is important on IE/Edge, it's recommended to duplicate it via SVGtransform
attribute. - While
transform
CSS is polyfilled for IE/Edge, unfortunately, it's impossible to polyfilltransform-origin
. Thus, where compatibility with IE/Edge is desired, it's recommended to only use the defaulttransform-origin
. - Most of the browsers currently have issues interpreting
transform-origin
CSS correctly. See issues for Chrome, Safari and Firefox. Most of this confusion should be resolved once CSStransform-box
is implemented. Wheretransform-origin
is important, it's recommended to also include the desiredtransform-box
CSS for future compatibility.
Triggering animation
The animation can be triggered via a trigger
attribute or an on
action.
trigger
attribute
Currently, visibility
is the only available value for the trigger
attribute. The visibility
triggers when the underlying document or embed are visible (in viewport).
For instance:
<amp-animation id="anim1" layout="nodisplay" trigger="visibility"> ... </amp-animation>
Triggering via on
action
For instance:
<amp-animation id="anim1" layout="nodisplay"> ... </amp-animation> <button on="tap:anim1.start">Animate</button>
on
actions
amp-animation
element exports the following actions:
-
start
- Starts the animation is it's not running already. Timing properties and variables can be specified as action arguments. E.g.anim1.start(delay=-100, --scale=2)
. -
restart
- Starts the animation or restarts the currently running one. Timing properties and variables can be specified as action arguments. E.g.anim1.start(delay=-100, --scale=2)
. -
pause
- Pauses the currently running animation. resume
- Resumes the currently running animation.togglePause
- Toggles pause/resume actions.seekTo
- Pauses the animation and seeks to the point of time specified by thetime
argument in milliseconds orpercent
argument as a percentage point in the timeline.reverse
- Reverses the animation.finish
- Finishes the animation.cancel
- Cancels the animation.