Buttons

Button Hover Effect

A button that lifts on hover and settles on press, using CSS transition — copy-ready.

Edit this in the studio

Opens with this animation loaded. Nothing is uploaded — the scene travels in the link.

animation.css
.button-lift {
  transform: translate3d(160px, 136px, 0);
  box-shadow: 0px 2px 8px 0px #00000040;
  width: 160px;
  height: 48px;
  background: #6366f1;
  border-radius: 12px;
  color: #ffffff;
  font-size: 15px;
  font-weight: 600;
  transition: transform 180ms ease-out, box-shadow 180ms ease-out, background 180ms ease-out;
}

.button-lift:hover {
  transform: translate3d(160px, 133px, 0);
  box-shadow: 0px 10px 24px 0px #6366f166;
  background: #7c6cff;
}

.button-lift:active {
  transform: translate3d(160px, 136px, 0);
  box-shadow: 0px 2px 6px 0px #00000040;
  transition: transform 90ms ease-out, box-shadow 90ms ease-out;
}

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

Why it is built this way

This is a transition on :hover, not a keyframe animation — the difference matters. Keyframes run on a fixed schedule; a transition follows the pointer, so it reverses cleanly when someone hovers away halfway through. The press state uses a shorter duration than the release, which is what makes a button feel responsive rather than mushy.

What it animates

No keyframes at all — this one is built from interaction states, so the browser only does anything when the visitor does.

What it costs to run

Nothing here runs on a timer. The motion lives entirely in :hover and :active, which compiles to a transition — so it costs nothing until the visitor does something, and it interrupts and reverses cleanly halfway through.

Accessibility

A reader who never triggers :hover and :active never sees this, so it carries no risk on load. Worth adding a :focus-visible state alongside it: as written, a keyboard user gets no feedback at all.

Related animations

buttonhovertransitionlift