CSS Animation in the age of tools

For years, any real animation on a web page meant JavaScript, a jQuery plugin, or a library like GSAP. Modern CSS can now do most of that on its own: state-change transitions, looping keyframe animations, and even effects that used to require JavaScript, like fading an element in as it enters the page, or as the user scrolls.

The goal today is not to memorize every property. It's to know what's possible, so you know what to ask an AI tool for, and so you can read and evaluate the CSS it hands back to you.

Ask:
"What are the main ways to animate something in CSS today? How is that different from how it was done 10 years ago with jQuery?" "When should I reach for a CSS animation instead of asking an AI to write JavaScript for the same effect?"
Notes

Transitions — Animate a State Change

The simplest form of animation: tell the browser that when a property changes, like on hover, focus, or a class being added, it should animate smoothly between the old and new value instead of jumping instantly.

button {
  background-color: #4466cc;
  transition: background-color 0.3s ease, transform 0.3s ease;
}
button:hover {
  background-color: #cc3333;
  transform: scale(1.1);
}

CSS Transitions @ w3schools

Ask:
"What does the CSS transition property actually do? What are transition-property, transition-duration, and transition-timing-function?" "What's the difference between ease, linear, and ease-in-out as timing functions? When would I pick each one?"
Notes

@keyframes and animation — Animate Over Time

Transitions only animate between two states. For anything that loops, or moves through several steps on its own (no hover needed), use @keyframes to define the steps, then the animation property to play them.

.circle {
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1);   opacity: 1;   }
  50%      { transform: scale(1.4); opacity: 0.6; }
}

CSS Animations @ w3schools

Ask:
"What is @keyframes and how is it different from the transition property? When would I use one over the other?" "What do animation-iteration-count, animation-direction, and animation-fill-mode each control?"
Notes

transform — Move, Rotate, Scale, Skew

transform is what actually moves, spins, resizes, or slants an element. It's usually combined with transition or animation, transform on its own just repositions the element instantly.

translate
rotate
scale
skew

Hover each box

.demo-translate:hover { transform: translateY(-15px); }   /* move    */
.demo-rotate:hover    { transform: rotate(20deg);     }   /* rotate  */
.demo-scale:hover     { transform: scale(1.3);        }   /* resize  */
.demo-skew:hover      { transform: skewX(-15deg);     }   /* slant   */

CSS 2D Transforms @ w3schools

Ask:
"What is the CSS transform property? What do translate, rotate, scale, and skew each do?" "Why does transform: translateY() not affect the layout of elements around it, the way changing margin-top would?"
Notes

New: Animating Things That Used to Need JavaScript

Until recently, you could not animate an element appearing from display: none, the browser just snapped it into existence with no transition. Two newer CSS features fix that: @starting-style and transition-behavior: allow-discrete.

This card fades and slides in and out, animating all the way from display: none. No JavaScript animation code, just CSS.
.card {
  display: none;
  opacity: 0;
  transform: translateY(-10px);
  transition: opacity 0.35s ease, transform 0.35s ease,
              display 0.35s allow-discrete;
}
.card.is-open {
  display: block;
  opacity: 1;
  transform: translateY(0);
}

/* tells the browser what "before the animation" looks like,
   since a display:none element has no prior state to animate from */
@starting-style {
  .card.is-open {
    opacity: 0;
    transform: translateY(-10px);
  }
}

Baseline newly available since August 2024. Works in current Chrome/Edge, Firefox, and Safari.

CSS @starting-style Rule @ w3schools

Ask:
"What problem does @starting-style solve? Why couldn't you animate display: none before?" "What does transition-behavior: allow-discrete actually mean? Which CSS properties need it?"
@starting-style + transition-behavior: allow-discrete reached Baseline "newly available" in August 2024. Supported in Chrome/Edge 117+, Firefox 129+, Safari 17.4+. This is the modern replacement for the old jQuery slideToggle()/fadeIn() pattern, worth pointing out explicitly since students may have seen that pattern in older tutorials or from AI models trained on older data.

Scroll-Driven Animations (Emerging)

Newer still: animations that play based on scroll position instead of time, no JavaScript scroll listener required. animation-timeline: view() plays an animation as an element scrolls into and out of its scroll container.

Scroll inside the box below

scroll down ↓
I fade and slide in as I scroll into view
keep scrolling ↓
Me too
(end)
.target {
  animation: fadeIn linear;
  animation-timeline: view();       /* tied to scroll position, not time */
  animation-range: entry 0% cover 40%;
}
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0);     }
}

Support note: this one is not fully cross-browser yet. It works in Chrome, Edge, and Safari, but not yet in Firefox, so it should not be the only way you build something essential. If you don't see the demo above animate as you scroll, that's why.

Ask:
"What is animation-timeline: view() and how is it different from animating based on time?" "If a CSS feature isn't supported in every browser yet, how do I write a fallback so the page still works there?"
Scroll-driven animations (animation-timeline: scroll()/view()) are "Limited availability," Chrome/Edge 115+ and Safari 26+ support it, but Firefox has a positive standards position without an implementation yet as of testing this in August 2026. Worth flagging as "know it exists, check caniuse.com before relying on it in a real project."

Don't Forget: prefers-reduced-motion

Animation isn't free for every visitor. Some people get real physical discomfort, dizziness or nausea, from motion on screen, and most operating systems let them turn on a system-wide "reduce motion" setting. CSS can detect that setting and respect it.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

Any page with real animation, especially anything that loops or moves automatically like the pulsing circle earlier in this slide, should include a rule like this.

CSS Accessibility (prefers-reduced-motion) @ w3schools

Ask:
"What is prefers-reduced-motion and who is it for? How do I add support for it to a page that already has CSS animations?"
Notes