view()

Saleh Mubashar on

Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.

Experimental: Check browser support before using this in production.

The view() function tracks the progress of an element within a scrollable viewport (the nearest scroll container), when used in the animation-timeline property. It works similarly to JavaScript’s Intersection Observer API in creating scroll-driven animations, except that it’s fully built into CSS.

.element {
  animation: reveal 1s linear both;
  animation-timeline: view();
}

It can create animations that are linked to the visibility of the content as it enters and exits the scrollport. In other words, instead of an animation that runs for a certain amount of time, it runs based on the element’s position when scrolling.

The view() function is defined in the Scroll-driven Animations Module.

Syntax

The view() function can only be used with the CSS animation-timeline property.

animation-timeline:  view([ <axis> || <'view-timeline-inset'>]?);

Arguments

/* No parameters */
animation-timeline: view();

/* Axis */
animation-timeline: view(block); /* Default */
animation-timeline: view(inline);
animation-timeline: view(y);
animation-timeline: view(x);

/* Inset */
animation-timeline: view(auto); /* Default */
animation-timeline: view(25%);
animation-timeline: view(150px);
animation-timeline: view(25% 30%);
animation-timeline: view(30% 240px);
animation-timeline: view(120px 200px);
animation-timeline: view(auto 100px);

/* Axis and Inset */
animation-timeline: view(block auto); /* Default */
animation-timeline: view(inline 15%);
animation-timeline: view(x 140px auto);

By default, the axis is block (the direction perpendicular to the text flow). Unlike the scroll() function, you cannot manually define a scroller as it always uses the nearest scrollable ancestor.

axis

You can specify the scroll axis using one of these values:

  • block (default): Scroll axis in the block direction (usually vertical for horizontal text flows).
  • inline: Scroll axis in the inline direction (usually horizontal).
  • y: Vertical scroll axis.
  • x: Horizontal scroll axis.

Note: If the chosen axis doesn’t correspond to an actual scrollbar (e.g. x is used but the element only scrolls vertically), the animation timeline will be inactive and no progress will be tracked.

view-timeline-inset

The view-timeline-inset optional argument allows you to adjust the animation’s range relative to its visibility within the scrollport. Think of it as setting boundaries inside the scrollport to control when the animation starts and ends. Inset values don’t refer to the percent visible area of the element. Instead, they refer to its position relative to the scrollport edges.

A positive inset will shift the bounds inwards from the edges of the scrollport, delaying the start or ending the animation early. A negative value does the opposite — it expands the visible range, so the animation starts earlier.

  • auto (default): No adjustment; the timeline will use the scroll-padding value to determine the bounds.
  • <length-percentage>: Accepts one or two values to customize start and end insets. The value can be a percentage or a length unit. For example:
    • view(20%): The animation starts when the element is 20% visible in the scrollport.
    • view(10% 30%): The start and end insets are set separately.

Bramus has a vast collection of live demos where you can see this concept in action.

Basic usage

The CSS view() function is used for scroll-driven animations, so let’s do exactly one of those. You can animate elements based on their visibility within the viewport, such as fading in sections as the user scrolls.

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

.element {
  animation-name: fadeInUp;
  animation-timeline: view();
  animation-range: entry 0% exit 100%;
}

This animation is driven by the view() timeline — meaning the keyframe progress is tied to how much of the element is visible inside the scrollport, not the scroll position itself.

Note: When using the animation shorthand, make sure to declare animation-timeline after it. The shorthand resets animation-timeline to auto, so any earlier value gets overridden.

Experimenting with inset values

The inset values in the view() function can be a bit confusing at first. But once you understand how they work, they give you a lot of control over when animations start and end as elements enter and exit the scrollport.

For example, let’s say you want to delay the animation until the element is slightly inside the viewport. You can do that with:

animation-timeline: view(100px);

This tells the animation to begin only after 100px of the element is visible from the bottom edge of the scrollport. But there’s an important detail: when you pass a single value like this, it’s treated as both the start and end inset. In other words, view(100px) is shorthand for view(100px 100px). That means the animation will also end early, before the element has fully exited the scrollport.

To delay just the start while letting the animation run until the element leaves the viewport, you can provide two values: view(0 100px).

Note: If you’re delaying the animation using something like view(100px), the element might show up already in its final state. To avoid this and ensure it starts from the correct visual state, use: animation-fill-mode: both.

You may have noticed that the view timeline animation finishes just as the element exits the viewport. This is because the timeline reaches 100% only when the element has completely left the viewport, so you never get to see the complete animation. You can fix this by ending the animation earlier using a second inset value:

animation-timeline: view(80% 100px);

The animation will now start once 100px of the element is inside the scrollport (measured from the bottom edge of the scrollport), and it will end when the element reaches 80% down from the top of the scrollport.

Don’t get confused by the order of the values — here’s a helpful way to think about it:

  • When scrolling down, the first value (80%) defines where the animation ends, measured from the top of the scrollport.
  • The second value (100px) defines where the animation starts, measured from the bottom of the scrollport.

Here’s what this would look like:

Examples

Let’s look at two real-world use cases for the CSS view() function.

Reveal images on scroll

Here’s an example that reveals an image as it scrolls into view:

The image fades in and scales up from the bottom-left corner as it enters the viewport. It uses a view() timeline with an inset (view(80% 0)), meaning the animation kicks in as soon as the image enters and finishes early—around 80% down the scrollport.

View timeline with CSS Carousels

You can use view timelines pretty effectively with CSS Carousels. In the example below, carousel items fade in as you scroll or click through using the navigation buttons:

We’re setting the axis to horizontal and using a 90% inset so the animation finishes a bit earlier. This is important because without it, the last slide doesn’t fully fade in, even when you scroll all the way to the end. The 0 ensures the animation starts as soon as a slide enters the view.

animation-name: fadeIn;
animation-fill-mode: both;
animation-duration: 1s;
animation-timeline: view(x 90% 0);

Staggered animations

Rather than having a boring display of lists on your website, you can spice it up a bit by animating lists or groups of elements in sequence as they come into view.

<ul>
  <li class="list-item" style="--order: 0;">Item 1</li>
  <li class="list-item" style="--order: 1;">Item 2</li>
  <li class="list-item" style="--order: 2;">Item 3</li>
</ul>
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.list-item {
  animation-name: fadeIn;
  animation-duration: auto;
  animation-timeline: view();
  animation-range: entry 0% exit 100%;
  animation-delay: calc(var(--order) * 100ms);
}

Scroll-triggered text highlight

This is another interesting animation you can use to bring life to your websites: animating text highlights as the user scrolls through content.

<p class="highlighted-text">This text gets highlighted from left to right as it scrolls into view.</p>
@keyframes highlightSweep {
  from {
    background-size: 0% 100%;
  }
  to {
    background-size: 100% 100%;
  }
}

.highlighted-text {
  background-image: linear-gradient(to right, yellow 100%, transparent 0%);
  background-repeat: no-repeat;
  background-size: 0% 100%;
  background-position: left center;

  animation-name: highlightSweep;
  animation-timeline: view(20%);
  animation-fill-mode: forwards;
  animation-duration: auto;
}

This example highlights a paragraph of text as it enters 20% of the viewport. As the .highlighted-text element enters the viewport, its background color transitions to yellow, and remains yellow till it leaves the viewport due to the animation-fill-mode set to forwards added.

view() vs. scroll()

view() Functionscroll() Function
PurposeTracks an element’s visibility progress within a specific view (e.g., viewport or scroll container).Tracks scroll progress of a scroll container (e.g., viewport or overflow element).
Syntaxview([axis] [inset])scroll([scroller] [axis])
Main Use CaseAnimates based on how much of an element is visible in a view timeline.Animates based on the scroll position of a scroll container.
Timeline TypeView Timeline: Tied to an element’s entry/exit in a view.Scroll Timeline: Tied to the scroll position of a container.
LimitationsLimited to visibility-based animations; requires a subject element.Limited to scroll-based animations; less detailed for element-specific visibility.

You can use view() when you need animations tied to an element’s visibility (e.g., fade-ins as an element enters the viewport), and scroll() for animations driven by the scroll position, like progress bars.

Browser support

Specification

The CSS view() function is defined in the Scroll-Driven Animations specification which is currently in Editor’s Draft status as of June 2025. That means the information in the specification can change between now and when the feature becomes a formal Candidate Recommendation, so refer to the Browser Support section before using it in a production environment.