Free · Fast · Privacy-first

CSS Animation Delay

Animation delay is where CSS timing control gets subtle.

Set precise delay in milliseconds or seconds

🔒

Generate stagger patterns for list items automatically

Fill-mode selector with visual explanation of each option

Preview the delay period to see the pre-animation state

Cost
Free forever
Sign-up
Not required
Processing
In your browser
Privacy
Files stay local
FreeNo signupWhite-label

Add this Animation Builder to your website

Drop the Animation Builder into any page — blog post, product docs, intranet, school portal — with a single line of HTML. Your visitors get the full tool, processed entirely in their browser. No backend, no uploads, no signup.

  • Files stay 100% in the visitor's browser
  • Responsive — adapts to any container width
  • Free forever, no API key needed

Embed code

<iframe
  src="https://www.fixtools.io/css-tool/animation-builder?embed=1"
  width="100%"
  height="780"
  frameborder="0"
  style="border:0;border-radius:16px;max-width:900px;"
  title="Animation Builder by FixTools"
  loading="lazy"
  allow="clipboard-write"
></iframe>

Attribution-friendly: a small "Powered by FixTools" link appears in the embed footer.

How animation-delay Works, Why Staggering Matters, and the fill-mode Trap

The animation-delay property defers the start of a CSS animation by a specified duration after the animation is applied to the element. A delay of 0.3s means the animation begins 300 milliseconds after the element renders or after the class containing the animation is added. Delays have two common applications. The first is sequencing: a page section should wait for a previous element to finish animating before it begins. The second is staggering: a group of elements should animate in sequence with a small delay between each, creating a cascading entrance effect that guides the eye across a list, grid, or navigation. A 0.1 second step between list items produces a crisp cascade; a 0.2 to 0.3 second step produces a slower, more deliberate reveal.

Staggered delays for lists work by applying progressively larger animation-delay values to each item in the group. In CSS, this uses nth-child selectors: li:nth-child(1) has animation-delay: 0s, li:nth-child(2) has animation-delay: 0.1s, and so on. In JavaScript frameworks, the delay is calculated from the item index: style={{ animationDelay: `${index * 100}ms` }}. The stagger step should be kept between 50ms and 120ms for most cases. A step below 50ms is imperceptible on most displays. A step above 150ms makes a six-item list feel slow, because the last item does not begin animating until 750ms after the first, and the user has been watching the list load for nearly a second.

The fill-mode trap is the most common CSS animation timing bug. Without animation-fill-mode: both, an element with a positive delay briefly shows in its final animated state before the animation begins. This happens because the browser applies the animation property to the element immediately, before the delay has elapsed, but does not yet apply the 0% keyframe state. The result is a visible flash of the element at its base style (often fully visible, fully opaque) during the delay, then a jump to the 0% keyframe state when the animation starts. Setting animation-fill-mode: both solves this by applying the 0% keyframe state throughout the delay period and holding the 100% keyframe state after the animation ends. Always set fill-mode: both when using positive delay.

Stagger patterns in production frameworks deserve dedicated patterns rather than ad-hoc nth-child rules. In React, a higher-order component or custom hook can return the appropriate animationDelay style based on the item index passed in, centralizing the stagger logic so every list across the app uses the same step value. In Vue, a directive or composable serves the same role. In Svelte, a single utility function generates the style string. The advantage of centralizing this logic is that changing the global stagger step from 80ms to 60ms becomes a one-file edit rather than a hunt across components. Teams that adopt a shared stagger utility report fewer inconsistencies between sections of the app and faster review cycles, since reviewers no longer need to verify each list's stagger timing independently.

How to use this tool

💡

Set the animation delay value. Enable stagger mode to generate delay values for multiple elements with a configurable step between each. Set fill-mode to both to prevent the pre-animation flash. Preview includes the delay period so you see the full timing.

How It Works

Step-by-step guide to css animation delay:

  1. 1

    Set the animation delay

    Enter the delay value in milliseconds or seconds. For a single element that should wait for a hero to finish, try 300 to 500ms. For list item stagger, keep the step between 80ms and 120ms.

  2. 2

    Set fill-mode to both

    Select animation-fill-mode: both in the controls. This prevents the element from flashing its base style during the delay period and holds the final keyframe state after the animation ends.

  3. 3

    Enable stagger mode for multiple elements

    Turn on stagger mode and set the number of elements and the step size. The generator outputs individual animation-delay declarations for each nth-child selector at the specified step.

  4. 4

    Copy and verify the delay in context

    Click Copy Code and apply the animation to your elements. Test in the browser by watching the full page load sequence, paying attention to whether any element flashes before its animation starts.

Real-world examples

Common situations where this approach makes a real difference:

Hero section sequential reveal

A landing page developer staggers three elements in the hero: the headline at 0ms delay, the subheadline at 200ms, and the CTA button at 380ms. Each uses a 400ms fade-up animation with fill-mode: both. The stagger guides the visitor's eye from the headline down to the call to action in a deliberate sequence that feels designed rather than incidental.

Dashboard metric card cascade

A SaaS dashboard shows six metric cards that cascade into view on first load. Each card uses an 80ms delay step via nth-child selectors: the first card appears immediately, the last after 400ms. The fill-mode: both setting ensures none of the cards flash their loaded state before their animation begins. The cascade completes in under half a second, giving the impression of a fast render.

Multi-step onboarding prompt

An onboarding overlay has four instruction steps that appear sequentially: each step has a 300ms duration and the next step's delay equals the sum of all previous durations plus a 100ms pause. The delay chain creates a reading rhythm that gives the user time to process each step before the next appears. Fill-mode: both holds each step visible after its animation completes.

Staggered navigation menu items

A mobile navigation menu opens and reveals seven items with a 60ms stagger step. Items use a slide-down from opacity 0 and translateY(-8px) to their final position. The 60ms step means all seven items finish appearing within 360ms of the menu opening, fast enough to feel snappy on a mobile device. Negative delays are used to pre-seed the first two items as partially visible when the menu opens.

When to use this guide

Use this when building staggered list entrances, sequential section reveals, or any animation that must start after a specific interval, and when you need the fill-mode set correctly to avoid pre-animation flashes.

Pro tips

Get better results with these expert suggestions:

1

Always set fill-mode: both when using positive delay

If there is one rule to memorize for CSS animation delay, it is this: any animation with animation-delay > 0 should also have animation-fill-mode: both. Without it, the pre-animation flash is almost guaranteed for fade-in and slide-in animations. The generator sets this by default; check it when editing animation shorthand by hand.

2

Cap stagger delay at 500ms for lists longer than six items

Add Math.min(index * stepMs, 500) when computing delays in JavaScript. Without a cap, a 10-item list with 100ms steps means the last item does not begin animating until 900ms after page load. Users can perceive this wait and may scroll past items that have not yet appeared. A 500ms cap lets all items finish loading within a second of the first.

3

Use negative delay to offset looping animations in a group

For multiple spinner or pulse elements that should be at different points in the same loop, apply negative delays: -0.33s, -0.66s, and 0s for a three-element group on a 1-second loop. Each element starts at a different point in the cycle, creating an evenly distributed phase offset that looks like a coordinated sequence rather than three separate animations.

4

Test stagger timing with the DevTools Animations panel scrubber

Open the DevTools Animations panel and reload the page while it is open. The panel shows every CSS animation as a timeline bar, making the stagger offsets visible at a glance. Scrub through the timeline to verify that each element starts at the correct offset relative to the previous and that fill-mode holds the pre-animation state throughout each delay period.

FAQ

Frequently asked questions

animation-delay specifies how long the browser waits after the animation property is applied before the animation starts playing. During the delay, the element shows its base CSS styles unless animation-fill-mode: backwards or both is set, in which case it shows the 0% keyframe state. A delay of 0s (the default) starts the animation immediately. Negative delay values are valid and skip forward into the animation timeline by that amount, useful for making a staggered group of animations appear to be mid-sequence when the page first loads.
This is the fill-mode bug. When animation-fill-mode is not set or is set to none, the element shows its base CSS style during the delay period and then jumps to the 0% keyframe state when the animation starts. If the base style and the 0% keyframe differ (as they do in a fade-in where 0% is opacity: 0 and the base is opacity: 1), the element is visible during the delay and then disappears before the animation starts. Setting animation-fill-mode: both makes the element hold the 0% state throughout the delay, which is the correct behavior for most animations with positive delays.
For a list of four to eight items, a step of 80 to 100ms per item produces a clean cascade that finishes in under 600ms total. For longer lists of ten or more items, reduce the step to 40 to 60ms to prevent the last items from feeling delayed. For very short lists of two or three items, a step of 120 to 150ms is acceptable and creates a more deliberate reveal. Beyond 200ms per step, the stagger begins to feel sluggish and users may perceive the page as slow to render.
Forwards holds the element at the 100% keyframe state after the animation finishes, preventing it from snapping back to its base style. Backwards holds the element at the 0% keyframe state during the delay period, preventing the flash of base styles. Both applies forwards and backwards simultaneously: the element shows the 0% state during any delay and holds the 100% state after completion. For animations with a positive delay that should persist after completion, both is almost always the correct value.
Yes, and it is useful for making animations appear to be in progress when the page loads. A delay of -0.5s on a 1-second animation starts the element at the 50% keyframe point. This is used for staggered groups where you want early items to appear further along the sequence when the page first renders, giving the impression that the animation has been running for a moment already. Negative delays are also used in looped animations to offset multiple elements so they are at different points in the same loop cycle simultaneously.
In a JavaScript framework, map over the items array and set an inline animationDelay style based on the index: items.map((item, i) => <li style={{ animationDelay: `${i * 80}ms` }}>{item}</li>). In vanilla JS, select all the list items and set the style in a forEach loop. For large lists, consider capping the maximum delay at 500ms: Math.min(i * 80, 500). Items beyond the cap start simultaneously, preventing the last item in a 20-item list from waiting 1.6 seconds to appear.
No. The delay simply defers when the animation starts; it has no effect on how the animation is processed once running. The browser does not pre-compute compositor layers during the delay period, so there is no memory overhead associated with multiple pending delayed animations. The performance implications of the animations themselves (compositor-thread versus paint-triggering properties) apply equally regardless of whether a delay is set. Even a stagger of fifty elements adds no measurable cost during the pre-start period.
Set the delay of each subsequent animation to be the duration of all previous animations combined. If animation A is 300ms and animation B should start immediately after, set B's delay to 300ms. If animation C follows B which is 400ms, set C's delay to 700ms. This approach works for simple linear sequences. For complex choreography with branching or conditional timing, a JavaScript animation library offers more manageable sequencing. For three to five sequential CSS animations, the manual delay approach is straightforward and maintainable. Document the chain with comments in the stylesheet noting the implicit start time of each step so future maintainers do not have to recompute the cumulative durations when adding or removing an animation from the middle of the sequence.
Yes. The animationstart event fires after the delay has elapsed and the first keyframe begins playing, not at the moment the animation property is applied to the element. If you need a callback at the moment the animation is scheduled but before the delay starts, hook into the class application or property change yourself since CSS provides no event for that point in the lifecycle. The animationend event fires once at the end of each iteration only when iteration-count is not infinite, or at the end of the iteration that completes the count. For staggered groups, listen for animationend on the last item to detect when the entire group has finished revealing.
Yes. The animation-delay property defers only the very first iteration. Subsequent iterations follow back-to-back at the duration value with no additional delay between them. If you need a gap between iterations of a looping animation, the delay value alone does not produce that effect. Instead, build the gap directly into the @keyframes by holding the start state across multiple percentage stops. For example, in a 2-second animation that should pause for the first 500ms of each loop, set 0% and 25% to the same starting values and let the actual motion happen between 25% and 100%. This produces a per-iteration pause that animation-delay cannot achieve.

Related guides

More use-case guides for the same tool:

Ready to get started?

Open the full Animation Builder — free, no account needed, works on any device.

Open Animation Builder →

Free · No account needed · Works on any device