CodingBanana
CodingBanana
CSS Fundamentals

CSS Animations and Keyframes

10 min read📖 Intermediate
CSS animations let elements animate automatically on their own — no hover or click needed. You define the steps with @keyframes and attach them with the animation property.

Let me ask you something.

Have you ever landed on a website and the heading slides in from the left as the page loads? Or seen a loading spinner rotating in a circle? Or a notification that pulses gently to grab your attention?

None of that required JavaScript. It was pure CSS animations.

Transitions are great but they need something to trigger them — a hover, a click, a focus. Animations are different. They run on their own. The moment an element appears on the page the animation starts. No user interaction needed.

Transitions vs Animations

Before we go further let me make sure this distinction is clear.

  • Transitions — animate between two states. They need a trigger. Hover, focus, active. You define the start and end and CSS handles the in between.
  • Animations — run automatically. No trigger needed. You define multiple steps and CSS loops through them. They can repeat, reverse, and run forever if you want.

Think of a transition like a light switch. It goes from off to on when you flip it. An animation is like a traffic light. It cycles through states on its own continuously.

@keyframes — Defining the Animation

To create an animation you first define what it does using @keyframes. This is where you describe each step of the animation.

@keyframes animation-name {
  from {
    /* starting state */
  }
  to {
    /* ending state */
  }
}

from is where the animation starts. to is where it ends. CSS handles everything in between automatically.

Then you attach it to an element using the animation property.

Let us start with something simple. A pulsing red glow on the Netflix logo.

The Netflix logo now gently fades in and out continuously. Here is what is happening.

  • @keyframes pulse — defines an animation called pulse. It starts at full opacity and ends at half opacity.
  • animation: pulse 2s ease-in-out infinite — attaches the animation to the logo. Let us break down each value.
  • pulse — the name of the keyframes to use.
  • 2s — the animation takes 2 seconds to complete one cycle.
  • ease-in-out — the timing function. It eases in and out making the pulse feel smooth and natural.
  • infinite — the animation repeats forever. Remove this and it only plays once.
💡

The animation property follows this order: name, duration, timing-function, delay, iteration-count, direction. You do not need to write all of them every time. The most common pattern is just name, duration, and infinite for looping animations. Everything else defaults to sensible values.

Using Percentage Steps

Instead of just from and to you can define multiple steps using percentages. 0% is the start, 100% is the end, and anything in between is a middle step.

This is how you create more complex animations with multiple stages.

The logo now pulses with a red glow at the halfway point of the animation and then fades back. Three steps — start, middle, end.

  • 0% — the starting state. Full opacity, no glow.
  • 50% — halfway through. Slightly faded with a red text shadow glowing behind it.
  • 100% — back to the start. Full opacity, no glow.

Because 0% and 100% are identical the animation loops seamlessly. You cannot tell where one cycle ends and the next begins.

animation-direction: alternate

Instead of jumping from 100% back to 0% at the end of each cycle you can make the animation reverse smoothly using alternate.

The logo fades out then fades back in smoothly. alternate makes the animation play forward then backward then forward again in a continuous smooth loop.

Instead of jumping back to 0% when it hits 100% the animation reverses direction. It plays from to to then to back to from again. This is much smoother than manually making 0% and 100% match.

A Loading Spinner

Spinners are everywhere. Loading states, processing indicators, buffering icons. Here is how to make one with a pure CSS rotation animation.

A red spinning circle. Clean, simple, and exactly what you see on loading screens everywhere. Here is what is happening.

  • border: 4px solid rgba(255,255,255,0.2) — a light transparent border on all four sides. This is the gray track of the spinner.
  • border-top-color: #E50914 — only the top border is red. As the element rotates this red section spins around the track.
  • border-radius: 50% — makes it a circle not a square.
  • animation: spin 0.8s linear infinite — rotates it continuously. linear timing is important here.
  • transform: rotate(0deg) to rotate(360deg) — rotates the element one full turn. Then it loops back and goes again.
💡

linear is the right timing function for rotation animations. ease or ease-in-out would make the spinner slow down and speed up which looks wrong. Spinners should feel mechanical and constant. linear gives you that.

Slide In on Page Load

This is something you see on almost every modern landing page. Content slides in from below as the page loads. It feels welcoming and dynamic.

When the page loads the content fades in while sliding up from 40px below its final position. It feels polished and intentional. Here is what is happening.

  • from — the content starts invisible (opacity: 0) and 40px below where it will end up (translateY(40px)).
  • to — the content ends fully visible (opacity: 1) and in its normal position (translateY(0)).
  • forwards — this is animation-fill-mode. It tells the animation to stay at its final state when it finishes instead of snapping back to the starting state. Without this the content would slide up and then jump back to being invisible.
  • ease-out — starts fast and slows down at the end. This feels like the content is settling into place.
💡

The combination of opacity going from 0 to 1 and translateY going from a positive value to 0 is the most used entrance animation on the entire web. Start with 30px to 50px of translateY and 0.6s to 0.8s duration for most hero content.

animation-delay — Staggering Multiple Elements

When multiple elements animate in at the same time it looks fine. But when each one enters slightly after the previous one it looks intentional and choreographed. You do this with animation-delay.

The heading slides in first. Then the first paragraph 0.2 seconds later. Then the second paragraph 0.2 seconds after that. Each element enters in sequence like a choreographed reveal. Here is what is happening.

  • opacity: 0 on .animate — all elements start invisible. Without this they would flash at full opacity before the animation starts.
  • animation-delay: 0.2s and 0.4s — each element waits a little longer before starting its animation. 0.2 seconds between each one creates a clean cascading effect.
  • forwards — each element stays visible after its animation completes. Without this they would all snap back to invisible once done.
💡

Keep stagger delays short. 0.1s to 0.2s between elements feels elegant. Longer than 0.3s starts to feel slow and impatient. The whole entrance sequence should complete within about 1 second total.

Building the Netflix Clone

Let us add animations to our Netflix clone. The hero content slides up on load. The logo pulses subtly. We add a loading spinner for when the page is buffering.

Here is what every animation is doing.

  • logoGlow — the Netflix logo pulses with a soft red glow every 3 seconds. The 0%, 100% pattern on the same state means it loops seamlessly.
  • slideUp on hero content — each element in the hero slides up from 40px below and fades in. The heading goes first, then the paragraphs, then the form.
  • opacity: 0 on .animate — all animated elements start invisible so there is no flash before the animation begins.
  • forwards on all entrance animations — every element stays visible after its animation completes. Without this they would all disappear the moment their animation finished.

Next up: you have already seen scale and translateY in action. Now let us learn the full power of what transform can do — rotate, scale, move, and skew elements with precision.

Learn about CSS Transform →

Have anything to say about this lesson?

Your feedback helps improve these tutorials. If something was confusing or missing, let us know.

We don't currently reply to feedback — but if we add that feature in the future, we'll reach out to you.