CSS animation-range-start and animation-range-end Guide

This article provides a concise overview of how the CSS animation-range-start and animation-range-end properties define the precise boundaries of scroll-driven animations. You will learn the mechanics behind these properties, the syntax and values they accept—including percentages, lengths, and named view-timeline ranges—and how they determine exactly when an animation starts and finishes along a scroll timeline.

Understanding Scroll Timeline Boundaries

In modern CSS scroll-driven animations, an animation's progress is mapped to scroll progress rather than elapsed wall-clock time. By default, an animation runs from the very beginning of the scroll container to the very end.

The animation-range-start and animation-range-end properties allow developers to override this default behavior. They define the specific scroll positions where the animation timeline begins (0% progress) and completes (100% progress), effectively segmenting the scroll area into active and inactive zones.

Syntax and Accepted Values

Both properties accept values that determine an offset along the scroll or view timeline. These values fall into three primary categories:

1. Percentages and Lengths

When using standard scroll timelines (such as scroll()), positions are typically declared using percentages or length values:

  • Percentages: Relative to the total scrollable overflow. animation-range-start: 20% begins the animation when the user has scrolled 20% down the container.
  • Lengths: Fixed distances such as px, vh, or rem. animation-range-end: 500px ends the animation when the scroll offset reaches 500 pixels.

2. Named Timeline Ranges

When using a view timeline (view()), the progress depends on the visibility of a subject element inside the scrollport. CSS provides predefined range names to target specific phases of element visibility:

  • cover: Spans from the moment the subject first enters the scrollport until it fully exits.
  • contain: Spans from the moment the subject is fully visible inside the scrollport until any part of it starts to leave.
  • entry: Spans from the moment the subject enters the scrollport until it is fully inside.
  • exit: Spans from the moment the subject begins to leave the scrollport until it has completely left.
  • entry-crossing: Spans from the moment the subject begins entering the scrollport until it crosses the opposite edge.
  • exit-crossing: Spans from the moment the subject begins exiting until it fully crosses the starting edge.

3. Named Ranges with Percentage Offsets

Named ranges can be combined with a percentage to fine-tune the boundaries:

.card {
  animation-range-start: entry 0%;
  animation-range-end: entry 100%;
}

In this example, the animation starts the instant the card enters the view and finishes as soon as it is fully visible, remaining static for the remainder of the scroll.

Default Values

The default value for both properties is normal.

  • On a standard scroll() timeline, normal resolves to 0% for animation-range-start and 100% for animation-range-end.
  • On a view() timeline, normal resolves to cover 0% for the start and cover 100% for the end.

The animation-range Shorthand

You can combine both properties into the animation-range shorthand property:

/* Syntax: animation-range: <start> <end>; */
.element {
  animation-range: entry 20% exit 80%;
}

If only one value is provided to the shorthand:

  • If the value is a named range without a percentage (e.g., animation-range: entry), it expands to cover the entire named range: entry 0% entry 100%.
  • If the value is a length or percentage (e.g., animation-range: 20%), it sets the start boundary to that value while the end boundary defaults to normal.

Example Implementation

The following example demonstrates a fade-in effect that begins as soon as the target element begins entering the screen and completes once it has entered by 50%:

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(40px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.animated-box {
  view-timeline-name: --boxTimeline;
  view-timeline-axis: block;

  animation-name: fadeIn;
  animation-timeline: --boxTimeline;
  animation-fill-mode: both;

  /* Configure the boundaries */
  animation-range-start: entry 0%;
  animation-range-end: entry 50%;
}

By constraining the boundaries with animation-range-start and animation-range-end, the animation reaches its final state early in the scroll cycle and remains fixed in place as the user continues scrolling.