ThisCalculator

Everyday

CSS Transitions on First Render: How to Trigger Them

Updated · Standard formula, shown below

CSS Transitions on First Render: How to Trigger Them

CSS transitions usually do not run when an element first appears because the browser has no earlier rendered value to transition from. To animate an initial appearance, give the element a starting style, then apply its destination style after the browser has registered that starting state.

Why transitions usually skip the first render

A transition animates a change between two computed values. For example, when an element’s opacity changes from 0 to 1, the browser can interpolate the intermediate values over time. But if the browser first encounters the element already at opacity 1, there is no earlier value to animate from: it simply paints the element in its current state.

This is why adding transition: opacity 300ms to an element does not, by itself, make it fade in. The transition property describes how later changes should be animated; it does not create a previous state or tell the browser to animate the initial paint.

There is another detail: browsers can combine style updates before painting. If a script adds an element and changes its class in the same turn of the event loop, the browser may see only the final style. Although your code changed the class, there may be no separately rendered starting state for the transition to use.

Use a starting class and a destination class

A reliable pattern is to render the element with its initial style, then add a class that supplies its final style. The following example fades and moves a panel into place:

.panel {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 300ms ease, transform 300ms ease;
}

.panel.is-visible {
  opacity: 1;
  transform: translateY(0);
}

For a page element, add is-visible after the initial document styles have been applied. For an element created by JavaScript, attach it first, then add the destination class on a later animation frame:

const panel = document.createElement("div");
panel.className = "panel";
panel.textContent = "Hello";
document.body.append(panel);

requestAnimationFrame(() => {
  panel.classList.add("is-visible");
});

requestAnimationFrame schedules the callback before a browser repaint. In this common pattern, the element is inserted with its starting class first, and the class change is then made in a later rendering opportunity, giving the browser a chance to recognize the two states. If a particular setup still batches the updates, use the two-frame variation below.

When to use one or two animation frames

One requestAnimationFrame is often enough for a newly inserted element, but rendering schedules and surrounding code can affect whether the initial state has been committed. If the transition does not start consistently, separate the starting style and destination style across two frames:

requestAnimationFrame(() => {
  requestAnimationFrame(() => {
    panel.classList.add("is-visible");
  });
});

The first callback gives the browser an opportunity to process the initial state; the second applies the destination state before a subsequent paint. This is a practical scheduling technique, not a requirement for every animation. Start with one frame and add the second only when needed.

Another option is to force a style calculation between the states:

document.body.append(panel);
panel.offsetWidth; // Read layout to make the browser calculate styles
panel.classList.add("is-visible");

Reading a layout-dependent property can make the browser calculate pending styles, so the class change becomes a distinct transition. This approach is sometimes called forcing reflow. It can be useful in a small, targeted case, but avoid repeatedly forcing layout in large updates: layout work can be costly, especially when many elements are involved. Prefer scheduling with animation frames when it is clear and dependable.

Choose the right technique for your case

  • Element already exists at page load: Apply the destination class after the initial render, often with requestAnimationFrame. If the page should not animate on every reload, consider whether an entrance animation is appropriate at all.
  • Element is inserted by JavaScript: Insert it with the starting style, then apply its destination class in a later frame.
  • Element appears when scrolled into view: Use an intersection observer to detect visibility, then add the destination class. This avoids animating every offscreen item immediately.
  • You need a one-time entrance effect: A CSS animation may be a better fit than a transition. Animations can define their own starting and ending keyframes and can run when the animation is applied.
  • You need to animate showing and hiding: Manage both states explicitly. A transition needs a change in a transitionable property, and an element set to display: none cannot visibly animate while it is not rendered.

Common problems and accessibility

The class is present from the start. If the element begins with both panel and is-visible, its first rendered style is already the destination. Remove the destination class initially, then add it after the starting state has been established.

The property cannot transition as expected. Transitions work for properties whose values can be interpolated, such as opacity, color, and transforms. Some properties do not transition smoothly, and discrete changes such as visibility or display do not behave like a continuous fade. For fading an element, transition opacity and handle its hidden state separately.

A stylesheet or script overrides the values. Check the computed styles in browser developer tools. A more specific selector, a later rule, or another script may cancel the intended starting or ending value. Also make sure the transition declaration applies to the element in both states.

The effect is too abrupt or never visible. Verify that the initial and final values differ, the duration is not zero, and the element is not hidden by an ancestor. For reduced motion preferences, provide a shorter or disabled effect where appropriate:

@media (prefers-reduced-motion: reduce) {
  .panel {
    transition: none;
  }
}

Respecting this preference gives people who have requested less motion a calmer experience. Keep important content available without requiring an animation to finish.

Transitions versus CSS animations

Use a transition when an existing element changes between states—for example, a button changing color on hover, or a panel opening after a user action. It is driven by a change in style values and usually has no effect until that change occurs.

Use a CSS animation when you want a defined sequence to run as an animation is applied. Keyframes can specify the opening and ending states:

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

.panel {
  animation: enter 300ms ease both;
}

The both fill mode applies the animation’s starting styles before it begins and its ending styles after it finishes. An animation can therefore be simpler for a one-off entrance, while a transition is often easier to reuse for interactive state changes. Neither choice eliminates the need to consider reduced motion and content visibility.

Frequently Asked Questions

Can CSS transition an element on page load?
Yes, if the browser gets a starting style and then a different destination style. Apply the destination after the initial state is established, commonly with requestAnimationFrame.

Why does adding a class not trigger my transition?
The browser may have processed the initial and final styles together, or the class may not change a transitionable computed value. Establish a distinct starting state, check computed styles, and try applying the destination class on a later frame.

Is a double requestAnimationFrame always required?
No. One frame is commonly sufficient. Use two when a single frame does not reliably separate the initial and destination states in your rendering setup.

Can I transition from display: none?
Not as a regular visible interpolation. The element is not rendered while its display is none. Use a transitionable property such as opacity for the visible effect, and handle when the element is removed from or added to layout separately.

Should I use a transition or an animation for a fade-in?
Either can work. A transition is suitable when you switch an element between defined states; a keyframe animation is often more direct for a one-time entrance with its own start and end sequence.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.