@keyframes

@keyframes <name> { from { … } <percentage> { … } to { … } }

A named course of an animation: which property values apply at the start, at the end and at any intermediate steps. It does not start anything by itself – it is used by the animation property with this name.

Values

  • from and to – the start and the end, the same as 0% and 100%.
  • percentages – intermediate steps in the range 0 to 100%. Positions with the same values can be joined with a comma: 0%, 100% { … }.
  • animation-timing-function inside a keyframe – the timing function for the segment from this keyframe to the next one.

Examples

Bouncing – three keyframes, the start and the end joined with a comma:

.ball {
  animation: bounce 0.8s ease-in-out infinite;
}
@keyframes bounce {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -20px; }
}

Even a single keyframe is enough. The browser fills in the missing to from the ordinary styles of the element, so the animation ends exactly where the element normally is – including its opacity of 0.9:

.message {
  opacity: 0.9;
  animation: slide-in 0.3s ease-out;
}
@keyframes slide-in {
  from {
    opacity: 0;
    translate: 0 -100%;
  }
}

A timing function in individual keyframes – the fall accelerates, the rise after the bounce decelerates:

.ball {
  animation: jump 1s both;
}
@keyframes jump {
  0% {
    translate: 0 -60px;
    animation-timing-function: ease-in;
  }
  60% {
    translate: 0 0;
    animation-timing-function: ease-out;
  }
  80% {
    translate: 0 -15px;
    animation-timing-function: ease-in;
  }
  100% { translate: 0 0; }
}

Things to watch out for

  • Declarations with !important are ignored inside @keyframes – the browser drops them, the other declarations of the keyframe still apply.
  • Two @keyframes rules with the same name are not merged: the whole last one applies. That can be used – a rule inside @media written later replaces the animation of the same name, for example for prefers-reduced-motion.
  • Properties that cannot change smoothly (for example justify-content) change in one step halfway through the segment in an animation.
  • The name is case-sensitive and must not be none.
  • Without a from or to keyframe the missing values are taken from the ordinary styles of the element – the animation thus continues smoothly from the state the element is in.

Browser support

Baseline – widely available: in all major browsers since September 2015, considered widely available since March 2018. Since version: Chrome 43, Firefox 16, Safari 9. As of October 2026 (MDN browser-compat-data).

Related:
animation
cubic-bezier() and steps()
transition
prefers-reduced-motion