Named Animation Ranges Explained
Part of Scroll Timeline Scoping & Ranges in Modern View Transitions & Scroll APIs.
The problem
A team adopts view timelines and sprinkles animation-range values copied from demos: entry, cover 0% cover 50%, contain, entry-crossing 50%. Some effects finish too early, some never finish on tall elements, and one only works on elements shorter than the viewport. Nobody can say, for a given element, at what scroll position entry 100% occurs — so every tweak is trial and error.
Each named range is defined by two edge crossings. Once those are clear, the right range for an effect can be chosen rather than guessed.
Root cause analysis: edges of the subject crossing edges of the scrollport
A view timeline tracks a subject element moving through a scrollport on one axis. For the block axis with normal scrolling, think of the subject moving up the screen: it enters at the bottom (the scrollport’s end edge) and leaves at the top (the start edge). Each range is a span of scroll positions between two events.
cover— from the subject’s start edge meeting the scrollport’s end edge (first pixel visible) to the subject’s end edge meeting the scrollport’s start edge (last pixel leaves). The full passage.contain— while the subject is fully inside the scrollport, or, if it is taller than the scrollport, while it fully covers it. From the later of “subject fully entered” or “subject covers scrollport”, to the earlier of the corresponding exit events.entry— from the first pixel entering until the subject is fully inside (or until it fills the scrollport, if taller). The subject’s own size decides how long this is.exit— the mirror of entry at the start edge.entry-crossing— from the subject’s start edge crossing the scrollport’s end edge until the subject’s end edge crosses that same scrollport edge. Its length is always the subject’s size, regardless of whether the subject is taller than the scrollport.exit-crossing— the mirror at the start edge.
Tall subjects change entry and contain. For a subject taller than the viewport, entry ends when the subject fills the viewport, which happens before its end edge arrives — so entry is shorter than entry-crossing. And contain becomes “while it covers the viewport” rather than “while it fits”. This is the usual cause of effects that behave differently on tall sections.
Percentages are relative to the range. entry 50% is halfway through the entry range. animation-range: entry 25% cover 50% starts a quarter of the way through entry and ends halfway through cover. Mixing range names this way is allowed and often needed.
Keyframes can name ranges. Inside @keyframes, selectors such as entry 0% and exit 100% attach keyframes to positions in different ranges, so one animation can fade in during entry and out during exit without two animations. The animation’s own animation-range should then be broad enough, usually cover, to contain every keyframe position.
Step-by-step resolution
Production code pattern
/* Reveal on arrival. */
.card {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 0% entry 80%;
}
@keyframes reveal { from { opacity: 0; translate: 0 24px; } }
/* In and out in one animation, using range names inside keyframes. */
.figure {
animation: in-and-out linear both;
animation-timeline: view();
animation-range: cover;
}
@keyframes in-and-out {
entry 0% { opacity: 0; scale: 0.96; }
entry 100% { opacity: 1; scale: 1; }
exit 0% { opacity: 1; scale: 1; }
exit 100% { opacity: 0; scale: 0.96; }
}
/* A progress line inside a tall section: runs while the section covers the viewport. */
.chapter__progress {
transform-origin: left;
animation: grow linear both;
animation-timeline: --chapter;
animation-range: contain;
}
.chapter { view-timeline: --chapter block; }
@keyframes grow { from { scale: 0 1; } }
@media (prefers-reduced-motion: reduce) {
.card, .figure, .chapter__progress { animation: none; }
}
Rendering Impact: composite. Ranges only decide which scroll offsets map to 0% and 100% of the animation; the properties animated are
opacity,translateandscale.
The in-and-out keyframes rely on animation-range: cover to include all four positions. With a narrower range, such as entry, the exit keyframes would fall outside the active range and never apply.
Inspecting ranges in DevTools
Chromium’s DevTools can show scroll-driven animations in the Animations drawer with their timelines, and scrubbing the page scroll updates their progress. For precise checks, log progress from script: element.getAnimations()[0].effect.getComputedTiming().progress at a given scroll position tells you exactly where in the range you are. Combining that with the element’s getBoundingClientRect() and the viewport height lets you verify the edge definitions above against your own layout, which is the fastest way to settle a disagreement about which range a design needs. The broader workflow is in profiling scroll-driven animations in DevTools.
Verification checklist
Constraints and trade-offs
containhas zero length when subject and viewport sizes are equal, so the animation jumps.entryandexitshorten for tall subjects, compressing effects.- Range names in keyframes need browser support for timeline range keyframe selectors.
- Insets from
view-timeline-insetshift every range’s edges together. - Ranges on horizontal timelines use inline edges, which reverse in right-to-left writing modes.
Frequently asked questions
What is the difference between cover and contain?
cover spans from the first pixel of the subject entering to the last pixel leaving. contain spans only while the subject is fully inside the viewport, or fully covers it if taller.
What is entry-crossing for?
It measures the subject’s start edge to end edge crossing the viewport’s end edge, so its length is always the subject’s size, unlike entry which is capped by the viewport.
Can I start in one range and end in another?
Yes. animation-range: entry 25% cover 50% starts a quarter through entry and ends halfway through cover.
Why don’t my exit keyframes apply?
The animation’s range probably does not include the exit range. Set animation-range: cover when keyframes reference both entry and exit.
Related
- Scroll Timeline Scoping & Ranges — the parent topic
- view-timeline-inset for Precise Triggers — moving the edges ranges are measured from
- Reveal on Scroll Without IntersectionObserver — entry ranges in practice