CSS view-timeline Property

The view-timeline property is a shorthand that defines a named scroll progress timeline based on an element's visibility within its scroll container.

selector { view-timeline: [ <view-timeline-name> [ <view-timeline-axis> ] ]; }
none Default value indicating the element does not define a named view progress timeline.
<custom-ident> A developer-defined name prefixed with two dashes used to identify the timeline.
block The scroll progress is measured along the block axis of the scroll container.
inline The scroll progress is measured along the inline axis of the scroll container.
y The scroll progress is measured along the vertical axis.
x The scroll progress is measured along the horizontal axis.

Code Examples

A basic example showing an element that fades and scales as it enters the viewport during a scroll.

<style>
  .spacer { height: 100vh; }
  .reveal-box {
    width: 200px; height: 200px;
    background-color: #3498db;
    margin: 50px auto;
    view-timeline: --box-reveal block;
    animation: fade-and-scale linear both;
    animation-timeline: --box-reveal;
  }
  @keyframes fade-and-scale {
    from { opacity: 0; transform: scale(0.5); }
    to { opacity: 1; transform: scale(1); }
  }
</style>
<div class="spacer"></div>
<div class="reveal-box"></div>
<div class="spacer"></div>

An advanced implementation using a sticky indicator that grows as the user scrolls, featuring a JavaScript support check.

<style>
  #scroll-container {
    height: 400px; overflow-y: scroll;
    background-color: #eeeeee;
    border: 2px solid #333333;
  }
  .content-block {
    height: 800px; padding: 20px;
  }
  .indicator {
    height: 10px; background-color: #e74c3c;
    width: 0%; position: sticky; top: 0;
    view-timeline: --scroll-path block;
    animation: progress-grow linear both;
    animation-timeline: --scroll-path;
  }
  @keyframes progress-grow {
    from { width: 0%; }
    to { width: 100%; }
  }
</style>
<div id="scroll-container">
  <div class="indicator" id="myIndicator"></div>
  <div class="content-block">
    <h2>Scroll down to see the progress bar grow</h2>
  </div>
</div>
<script>
  const indicator = document.getElementById("myIndicator");
  // Check if view-timeline is supported, otherwise fallback
  if (!CSS.supports("view-timeline", "--test block")) {
    console.log("View Timeline not supported. Using JS fallback logic.");
    indicator.style.backgroundColor = "#cccccc";
  }
</script>

Pro Tip

While you can use the view() function for quick one-off animations, using view-timeline is much better for complex scenes where multiple different elements need to react to the scroll progress of one specific target element.

Deep Dive

Think of view-timeline like a stopwatch that only ticks when an element is inside the viewer's window. Standard animations use time as a ruler, but view-timeline uses the element's position relative to the scrollport. It tracks an element's journey as it enters, crosses, and exits the visible area. You assign a custom name to this journey using a double-dash prefix, like --my-timeline. Once named, other properties like animation-timeline hook into this specific progress. It transforms the scroll position into a percentage from 0% (entry) to 100% (exit), giving you precise control over scroll-triggered visual effects without writing heavy JavaScript scroll listeners. This property combines view-timeline-name and view-timeline-axis into a single declaration.

Best Practices

Use clear, semantic names for your timelines to keep your CSS maintainable in large projects. Always define the axis explicitly if you are working with horizontal layouts to avoid the default block behavior. Pair this property with view-timeline-inset when you need the animation to start or end at a specific margin inside the scrollport rather than the exact edges.

Common Pitfalls

The most common mistake is forgetting the double-dash prefix for the timeline name. Also, if the parent container is not scrollable or the element is not positioned within a scrolling context, the timeline will have no progress and your animation will stay at the first frame. Note that display: none will destroy the timeline context entirely.

Accessibility

Scroll-linked animations can cause motion sickness for some users. Always wrap your scroll animation styles inside a @media (prefers-reduced-motion: no-preference) media query. This ensures that you only serve the motion-heavy experience to users who haven't expressed a preference for reduced movement.

Dev Data Table: view-timeline property

default none auto
animatable no
inherited no
experimental yes
year_intro 2022
year_standard 0
js_syntax_1 element.style.viewTimeline = "--my-timeline block";
js_syntax_2 element.style.setProperty("view-timeline", "--my-timeline block");
js_note When manipulating this property in JavaScript, ensure you include the required double-dash prefix for the timeline name string.
browsers { "Chrome": 115, "Edge": 115, "Firefox": 114, "Safari": 18, "Opera": 101, "Chrome Android": 115, "Safari on iOS": 18, "Samsung Internet": 23, "Opera Mobile": 77 }
results render here...