Why Is My CSS Transition Not Working?

A CSS transition usually stops working when the transition is placed on the wrong state, the property cannot be animated, the starting value is missing, or another CSS rule overrides the change.

CSS Animation Fix

Why is my CSS transition not working?

A CSS transition can look broken even when the syntax seems correct. The element may jump instantly, the hover state may change without animation, the accordion may open suddenly, or the effect may work in one direction but not the other. The real cause is usually one of a few things: the transition is on the wrong selector, the property cannot animate smoothly, the browser has no starting value, or another rule is overriding the final state.

  • CSS transition
  • Hover animation
  • Animatable properties
  • Motion debugging

What the bug looks like

The element changes instantly, only animates one way, ignores the transition, or jumps when it should slide, fade, lift, or expand smoothly.

Why it happens

CSS transitions only animate between known values for animatable properties. If the property cannot interpolate, there is nothing to animate.

What usually fixes it

Put transitions on the base state, animate transform or opacity when possible, define clear start/end values, and avoid transitioning display.

Error 1

The transition is only written on the hover state

This is one of the most common transition mistakes. If the transition is only declared inside :hover, the browser may animate when entering hover but snap back when leaving. The base element should know how to transition.

Broken code

Transition on hover only
.card:hover {
  transform: translateY(-6px);
  background: #fff5ef;
  transition: transform .2s ease;
}

Broken visual result

Snaps back
Card hover The card changes, but the reverse movement can feel abrupt because the base state has no transition.
Jump
The transition belongs on the normal state, not only on the changed state.

Correct code

Transition on base element
.card {
  transition:
    transform .2s ease,
    background .2s ease;
}

.card:hover {
  transform: translateY(-6px);
  background: #fff5ef;
}

Fixed visual result

Smooth both ways
Card hover The base element owns the transition, so the browser can animate in and out of the state.
Smooth
Put the transition on the element before the state changes.
Error 2

You are trying to transition display

display:none to display:block is not a smooth animation. The element is either in the layout or not. The browser cannot gradually interpolate between those two states.

Broken code

Display cannot fade
.menu {
  display: none;
  transition: display .2s ease;
}

.nav:hover .menu {
  display: block;
}

Broken visual result

Appears instantly
display: none → block not smooth
transition: display .2s ease bad target
The browser cannot animate display like opacity or transform.

Correct code

Opacity and transform
.menu {
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition:
    opacity .2s ease,
    transform .2s ease;
}

.nav:hover .menu {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

Fixed visual result

Fades and slides
opacity: 0 → 1 smooth
transform: translateY(8px) → 0 smooth
Animate properties the browser can interpolate smoothly.
Error 3

The changed property is not included in the transition

If you change transform but only transition background, the color may animate while the movement jumps instantly. The transition list has to include the property that changes.

Broken code

Wrong property listed
.box {
  transition: background .2s ease;
}

.box:hover {
  transform: translateX(80px);
  background: #ff6a3d;
}

Broken visual result

Movement jumps
Box movement The background can animate, but the transform is not in the transition list.
Jump
The property that changes must be part of the transition.

Correct code

Transition real changes
.box {
  transition:
    transform .2s ease,
    background .2s ease;
}

.box:hover {
  transform: translateX(80px);
  background: #ff6a3d;
}

Fixed visual result

Movement is smooth
Box movement Now both the movement and the background color have transition instructions.
Smooth
Transition the properties you actually change.
Error 4

The property causes layout jumps instead of smooth motion

Some properties can animate, but they are expensive or visually awkward because they force layout recalculation. Animating width, height, margin, or top can feel jumpy. For motion, transform is usually safer.

Broken code

Layout-heavy animation
.badge {
  width: 88px;
  transition: width .2s ease;
}

.badge:hover {
  width: 170px;
}

Broken visual result

Layout gets pushed
Expanding badge The element grows by changing layout size, which can push nearby content.
Wide
Changing layout dimensions can create visual instability around the element.

Correct code

Transform instead
.badge {
  transform: scale(1);
  transition: transform .2s ease;
}

.badge:hover {
  transform: scale(1.08);
}

Fixed visual result

Motion without layout push
Scaling badge The element feels animated without forcing surrounding layout to recalculate.
Scale
For motion, prefer transform and opacity when they fit the design.
Premium pattern

A production-minded transition pattern

A better transition setup is intentional. It defines a stable base state, animates predictable properties, respects reduced motion preferences, and avoids layout-heavy changes unless they are truly necessary.

Premium code

Smooth and safer
.card {
  transform: translateY(0);
  opacity: 1;
  border-color: #e5e7eb;
  box-shadow: 0 12px 28px rgba(15,23,42,.06);
  transition:
    transform .2s ease,
    border-color .2s ease,
    box-shadow .2s ease;
}

.card:hover,
.card:focus-within {
  transform: translateY(-4px);
  border-color: #ffd2c2;
  box-shadow: 0 18px 38px rgba(255,106,61,.12);
}

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

  .card:hover,
  .card:focus-within {
    transform: none;
  }
}

Premium visual result

Predictable motion
Production-ready transition

The card has a clear base state, a clear hover/focus state, smooth visual feedback, and a reduced-motion fallback.

Premium transitions are not just decorative. They are controlled, readable, and less likely to create layout instability.

Fast practical rule

If a CSS transition is not working, inspect whether the property actually changes. Then check whether that property is animatable, included in the transition list, and declared from a clear starting value on the base element.

Debug checklist

  • Put transition on the base element, not only on :hover.
  • Confirm the property you are changing is included in the transition list.
  • Check whether the property can actually animate smoothly.
  • Avoid trying to transition display:none to display:block.
  • Use opacity, transform, or max-height patterns when appropriate.
  • Define a clear starting value and ending value.
  • Check DevTools to confirm no stronger rule overrides the hover or active state.
  • Use prefers-reduced-motion for more respectful production UI.
Best first move Force the hover or active state in DevTools and check whether the property really changes.
Most common cause The transition is declared only on the changed state instead of the base element.
Most confusing cause The CSS is valid, but the property cannot animate the way you expect.
Better mindset A transition does not create a state change. It only smooths a state change that already exists.

Final takeaway

A CSS transition not working usually means the browser has no smooth path between two values. Either the transition is on the wrong selector, the wrong property is listed, the property cannot animate, or the final state is being overridden.

Start by proving that the property actually changes. Then make sure the base element owns the transition and the property can be interpolated. Once those pieces are correct, the transition becomes predictable instead of mysterious.

Want more fixes like this?

Browse more CSS interaction and layout debugging guides in the FrontFixer library.

Leave a Comment