From Transitions to Animations
The STO site already has motion in it. The tour cards lift slightly on hover. Buttons shift up when you point at them. Those effects are CSS transitions — and they are exactly the right tool for responding to user interaction. But what if you want the hero heading to fade in when the page loads? Or a badge to pulse on repeat to draw attention? Transitions cannot do either of those things. CSS animations can.
What transitions do well
Section titled “What transitions do well”A CSS transition watches a property for change and smoothly interpolates between the old value and the new one. The change always comes from outside — a :hover, a :focus, or a class added by JavaScript. Write the property you want to animate, how long the interpolation should take, and what easing to use:
.tour-card { transform: translateY(0); transition: transform 200ms ease, box-shadow 200ms ease;}
.tour-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md);}The browser watches transform and box-shadow. When the element enters the :hover state, it glides from the base values to the hover values over 200ms. When the cursor leaves, it glides back.
Transitions are ideal here — two states, user-triggered, clean code.
Where transitions fall short
Section titled “Where transitions fall short”Three things transitions cannot do:
They require a trigger. A transition only fires when a property value changes due to an event — hover, focus, a toggled class. You cannot make a transition run the moment a page loads without JavaScript to add a class at the right instant.
They only have two states. A transition goes from A to B. It cannot go A → B → C, or fade in while also sliding up and then pausing partway through.
They cannot loop. Once the property reaches its end value and the trigger is removed, the element snaps back. There is no way to say “keep doing this forever.”
These are not bugs — they are natural consequences of what transitions are for. But they leave gaps that CSS animations are specifically designed to fill.
What @keyframes unlocks
Section titled “What @keyframes unlocks”CSS animations introduce two new ideas: a @keyframes rule that defines the motion, and an animation property that applies it to an element.
The @keyframes rule describes a named sequence of steps. Unlike a transition, the motion is defined independently — it does not need a trigger, it can have as many steps as you want, and it can loop:
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; }}from is shorthand for 0% (the start of the animation) and to is shorthand for 100% (the end). You can add as many percentage steps between them as you need:
@keyframes slideUpFade { 0% { opacity: 0; transform: translateY(24px); } 60% { opacity: 1; } 100% { opacity: 1; transform: translateY(0); }}This is something a transition cannot express — three distinct states with independent timing for opacity and transform.
Writing a @keyframes rule does nothing on its own. It is a definition, like a function that has not been called yet. You connect it to an element using the animation property — which is what Lessons 02 and 03 cover.
Transitions vs animations at a glance
Section titled “Transitions vs animations at a glance”| Transitions | Animations | |
|---|---|---|
| Requires a trigger | Yes — hover, focus, or class change | No — can run automatically |
| Number of states | 2 (start and end) | Unlimited (0%–100%) |
| Can loop | No | Yes |
| Defined with | transition property | @keyframes + animation property |
| Best for | User-interaction responses | Page load effects, looping motion, sequenced steps |
Exercise
Section titled “Exercise”Part 1 — Observe the existing transition
Open style.css and find the .tour-card hover rule (or equivalent card/button hover rule from CSS M08). Read the transition declaration.
Ask yourself: can this transition play when the page first loads — before anyone hovers? Can it loop? Can it pass through more than two states? The answer to all three is no. Those constraints are not problems here — the transition is doing exactly the right job. But identifying them concretely is how you recognize when an animation is the better tool.
Part 2 — Write your first @keyframes rule
At the bottom of style.css, add a new section comment and write this rule:
/* === Animations === */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; }}Do not apply it to any element yet. The @keyframes rule is a definition — it sits in the stylesheet waiting to be used. In Lesson 02 you will learn the full @keyframes syntax, and in Lesson 03 you will apply animations to elements using the animation property. The fadeIn you just wrote will become the foundation of the STO hero entrance animation in Lesson 05.
- Transitions interpolate between two property values in response to a trigger — hover, focus, or a class toggle. They cannot auto-play, loop, or move through more than two states.
- CSS animations use a
@keyframesrule to define a named sequence of steps that can play automatically on page load, run through any number of states, and repeat. fromandtoare shorthand for0%and100%. You can place additional keyframe steps at any percentage between them.- A
@keyframesrule is a definition only — writing it does not animate anything until you apply it with theanimationproperty. - The
fadeInrule you wrote at the end of this lesson will be used in Lesson 05 to animate the STO hero section on page load.
Lesson 02 goes deeper into @keyframes syntax — multiple steps, animating more than one property, and naming conventions that keep your stylesheet readable as animations accumulate.