This proposal is an early design sketch by Blink Interactions team to describe the problem below and solicit feedback on the proposed solution. It has not been approved to ship in Chrome.
- Blink Interactions Team
- Introduction
- Goals
- Non-goals
- User research
- Use cases
- Proposed Solution: animation-trigger
- Detailed design discussion
- Considered alternatives
- Stakeholder Feedback / Opposition
- References & acknowledgements
Animations triggered by scrolling are common among pages on the web. For example, an author might do an animation to horizontally slide into view a section of a page that should now be visible based on the current vertical scroll position. These types of effects are usually achieved using JavaScript to both monitor the scroll position of interest and to trigger an animation in response. However for many of such use cases, all the information needed to create such effects can be made available declaratively. A declarative means of setting up such animations offers web authors a more convenient, reliable and performant option than common patterns of observing and evaluating scroll offsets via JavaScript.
Although the primary use of this project is expected to be via declarative CSS, it includes JavaScript interfaces which help to maintain parity between the Web Animation API and CSS Animations.
This project creates a more seamless experience of scroll-position-controlled web animations.
More convenient methods for creating scroll-position-controlled web animations.
N/A
When a section of a page is scrolled into view, it is introduced to the user via a smooth animation and when being scrolled out of view, it is slid out of view by a smooth reverse animation.
Take the example of a page divided into scrolling content on its right half and a gallery of images on its left. A different picture slides into the gallery on the left as you scroll content on the right side.
This project introduces a CSS property animation-trigger
which defines a "trigger condition" and
an "exit condition" for its associated animation.
animation-trigger
is a shorthand for the following CSS properties (also introduced by this
project):
animation-trigger-type
animation-trigger-timeline
animation-trigger-range-start
animation-trigger-range-end
animation-trigger-exit-range-start
animation-trigger-exit-range-end
animation-trigger-type
dictates how the trigger actions the playback of an animation.
It accepts the following keywords:
once
, which indicates that the animation should be played only the first time its trigger condition is met,repeat
, which indicates that the animation should be played forward each time its trigger condition is met and reset when its exit condition is met,alternate
, which indicates that the animation should be played forward each time its trigger condition is met and played backwards each time its exit condition is met, andstate
, which indicates that the animation should be played or resumed when its trigger condition is met and paused each time its exit condition is met.
animation-trigger-timeline
specifies the AnimationTimeline within which the trigger will evaluate whether its trigger or exit conditions have been met.
An AnimationTimeline might be time-based (DocumentTimeline) or scroll-based ScrollTimeline. Although this project is aimed at scroll-triggered animations, it is worth mentioning that the use of AnimationTimeline as the underlying source for a trigger leaves open the posibility of time-triggered animations in the future and allows scroll-triggered animations to integrate will with the rest of the animations ecosystem.
animation-trigger-range-start
and animation-trigger-range-end
define the range of the trigger's
timeline which when entered constitute the "trigger condition" being met.
animation-trigger-exit-range-start
and animation-trigger-exit-range-end
define the range of the trigger's
timeline which when exited constitute the "exit condition" being met.
Here is an example of how animation-trigger
might be declared:
@keyframe slidein {
from { transform: translateX(-100vw) }
to { transform: translateX(0vw) }
}
.target {
animation: slidein linear 1s forwards;
animation-trigger: view() repeat contain 0% contain 100% cover 0% cover 100%;
transform: translateX(-100vw);
}
.scroller {
overflow-x: hidden;
overflow-y: scroll;
}
The above example setups up an animation that will slide .target
from left (outside) of the screen
into the screen as soon as its scroll container is scrolls (vertically) so that .target
is fully
contained within its scroll container's scrollport.
It accomplishes this by specifying view()
as the timeline of the trigger. view()
sets up a
ViewTimeline within which
"contain 0% contain 100%" marks the boundaries of scrolling within which .target
is fully visible
and "cover 0% cover 100%" marks the boundaries of scrolling within which .target
is at least
partially visible. This creates a scenario in which, once .target
is fully in view (vertically
speaking) it is introduced into the scroll port and becomes visible to the user via a smooth
animation.
Use cases of scroll-triggered animations to typically be in view when their animation is playing. If scrolling happens so as to skip over the animations target entirely they might not want the animation to play. As such, specifying the triggering portion of the timeline as a range rather than a single point allows the author to avoid having their animation played when, for example, their page is loaded with a URL hash fragment such that the page immediately scrolls past the animation's target.
Some thought was given to modifying animation-play-state
, an existing CSS property, to incorporate
the new capabilities. However animation-play-state
serves a different purpose altogether.
It determines whether the an "active" animation is playing or paused whereas the trigger is
controlling where the animation should be considered active or not. More to add...
N/A at the moment. Will add when vendor positions requested.
Many thanks for valuable feedback and advice from:
- Yehonatan Daniv (TODO: add GitHub username)