CSS view-timeline-inset Property

This property adjusts the start and end positions of a view progress timeline by shifting the scrollport edges inward or outward.

selector { view-timeline-inset: [ <length-percentage> | auto ]{1,2}; }
auto The default value where no inset is applied and the scrollport edges are used as the timeline bounds.
<length-percentage> A specific length or percentage used to offset the start and end of the scroll progress timeline from the edges.

Code Examples

A basic example where the fade-in animation starts only after the element has traveled 20% into the scrollport.

div.box {
  view-timeline-name: --reveal;
  view-timeline-axis: block;
  view-timeline-inset: 20%;
  animation-name: fadeIn;
  animation-fill-mode: both;
  animation-timeline: --reveal;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

An advanced implementation using JavaScript to dynamically set the inset boundaries for a scale animation based on scroll progress.

<style>
  .container {
    height: 300px;
    overflow-y: scroll;
    background: #f4f4f4;
  }
  .target {
    margin-top: 500px;
    margin-bottom: 500px;
    width: 100px;
    height: 100px;
    background: #0000ff;
    view-timeline-name: --scroll-logic;
    animation: grow both;
    animation-timeline: --scroll-logic;
  }
  @keyframes grow {
    from { transform: scale(0.5); }
    to { transform: scale(1.2); }
  }
</style>

<div class="container" id="scrollBox">
  <div class="target" id="item"></div>
</div>

<script>
  const item = document.getElementById("item");
  // Set inset dynamically: 10% from top, 50px from bottom
  item.style.viewTimelineInset = "10% 50px";
  
  console.log("View timeline inset is now active.");
</script>

Pro Tip

You can use negative values to start an animation before the element even becomes visible in the viewport. This is great for pre-loading or prepping the state of an element so it is already in its animated state the moment the user sees it.

Deep Dive

Think of view-timeline-inset as a tripwire for your animations. By default, an animation starts the moment an element's edge touches the viewport. This property lets you move that tripwire. If you set a value of 100px, the animation won't trigger until the element has scrolled 100px into the view. It accepts one or two values. One value applies to both the start and end; two values allow you to set different offsets for the entrance and exit. This is part of the Scroll-driven Animations API, working alongside view-timeline-name to define how an element tracks its progress through the scroll container.

Best Practices

Use percentages rather than fixed pixel values when building responsive layouts to ensure the animation triggers consistently across different screen heights. It is best used to prevent animations from firing the split-second an element enters the screen, which can often be too fast for the user to notice. Stick to reasonable offsets so that the animation has enough room to actually complete before the element leaves the view.

Common Pitfalls

The biggest mistake is trying to use this without first defining a view-timeline-name or using the shorthand view-timeline. Also, remember that positive values move the boundary inward (shrinking the trigger zone), while negative values move it outward. If your inset values are too large, the trigger zone might vanish entirely, causing your animation to never run.

Accessibility

Scroll-driven animations can cause motion sickness for some users. Always wrap your animation logic in a prefers-reduced-motion media query. If a user has indicated they want less motion, you should either disable the animation or simplify it so it does not rely on the view-timeline-inset trigger logic.

Dev Data Table: view-timeline-inset property

default auto
animatable no
inherited no
experimental yes
year_intro 2022
year_standard 0
js_syntax_1 element.style.viewTimelineInset = "20% 10%";
js_syntax_2 element.style.setProperty("view-timeline-inset", "50px");
js_note When manipulating this via JavaScript, ensure the browser supports Scroll-driven Animations, otherwise the property will have no effect on the rendering.
browsers { "Chrome": 115, "Edge": 115, "Firefox": 0, "Safari": 0, "Opera": 101, "Chrome Android": 115, "Safari on iOS": 0, "Samsung Internet": 23, "Opera Mobile": 77 }
results render here...