How CSS view-timeline Controls Scroll Animations
The CSS view-timeline property allows developers to link
CSS animations directly to the visibility and position of a specific
element inside a scroll container or viewport. This article explains how
view-timeline functions, how it monitors an element's entry
and exit across the visible viewing area, and how related properties
like animation-timeline and animation-range
work together to create performant, scroll-driven visual effects without
JavaScript.
Understanding the View Timeline Concept
Traditionally, tying visual changes to an element's position on
screen required JavaScript event listeners (scroll events)
or the IntersectionObserver API. The CSS Scroll-Driven
Animations specification introduces view-timeline, which
shifts this workload entirely to the browser's native rendering
engine.
A view timeline is a scroll progress timeline where the progress is
determined not by the total length of the page, but by the relative
intersection of a target element (the "subject") with the scroll
container's visible area (the "scrollport"). The timeline progresses
from 0% to 100% as the subject moves from
entering the viewport to completely exiting it.
The Mechanics of
view-timeline
The view-timeline property is a shorthand for two
distinct sub-properties:
view-timeline-name: Declares an arbitrary custom identifier (prefixed with--) that represents the timeline.view-timeline-axis: Specifies the scroll direction to monitor, accepting values likeblock(default, typically vertical),inline(horizontal),y, orx.
When applied to an element, the browser begins tracking that element's coordinates relative to the scrollport edges:
.card {
view-timeline: --card-timeline block;
}Connecting Animations to the Timeline
Once defined, the timeline is connected to an animation using the
animation-timeline property:
@keyframes reveal {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
view-timeline: --card-timeline block;
animation-name: reveal;
animation-fill-mode: both;
animation-timeline: --card-timeline;
}Instead of running automatically over a fixed duration (like
2s), the animation's current time is bound directly to the
element's position along --card-timeline.
Controlling
Visibility Phases with animation-range
By default, a view timeline spans the entire duration of an element's
intersection with the scrollport—starting the moment the leading edge
touches the viewport (0%) and finishing the moment the
trailing edge leaves the viewport (100%).
To control precisely when the animation triggers, CSS provides the
animation-range property, which divides the timeline into
distinct phases:
cover(default): Spans from the moment the element begins to enter the scrollport until it has fully departed.entry: Spans from the moment the element begins entering the scrollport until it is fully inside.exit: Spans from the moment the element begins leaving the scrollport until it has fully cleared it.contain: Spans from the moment the element is fully inside the scrollport until it begins to leave.
For an entrance animation that completes as soon as the element is
fully visible, use the entry range:
.card {
view-timeline: --card-timeline block;
animation-name: reveal;
animation-timeline: --card-timeline;
animation-range: entry 0% entry 100%;
}Percentage offsets can also be passed directly to these ranges (for
example, entry 20% cover 80%), allowing fine-grained
control over trigger points.
Performance Advantages
Because view-timeline is handled natively by the
browser, animations can be offloaded to the compositor thread. This
prevents frame drops and layout thrashing, ensuring smooth animations
even when the main JavaScript thread is busy.