Suggest an editImprove this articleRefine the answer for “CSS properties for creating animations and smooth transitions”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**CSS transitions and animations** - two tools for motion on the web. `transition` reacts to state changes; `animation` with `@keyframes` runs on its own and can loop. ```css .btn { transition: transform 0.2s ease; } .btn:hover { transform: scale(1.04); } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .el { animation: fadeIn 0.3s ease-out forwards; } ``` **Key rule:** animate `transform` and `opacity` - they run on the compositor thread and skip layout recalculation.Shown above the full answer for quick recall.Answer (EN)Image**CSS transitions and animations** are two separate tools for adding motion to the web, and they solve different problems. ## Theory ### TL;DR - `transition` reacts to a state change (hover, focus, class toggle) and waits for a trigger - `animation` with `@keyframes` plays on its own - no trigger needed, can loop, can reverse - Main difference: `transition` is a single A to B change; `animation` is a sequence with as many steps as you define - Best for performance: animate `transform` and `opacity` - they run on the GPU and skip layout recalculation - Animating `width`, `height`, `top`, or `left` causes reflow every frame - use `transform` equivalents instead ### Quick example ```css /* transition: reacts to :hover */ .button { background: #3b82f6; transition: background 0.3s ease, transform 0.15s ease; } .button:hover { background: #1d4ed8; transform: scale(1.04); } /* animation: plays on its own, no trigger needed */ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .modal { animation: fadeIn 0.25s ease-out forwards; } ``` `transition` waits. `animation` just goes. ### transition: triggered changes `transition` takes four values: which property, how long, what easing, and an optional delay. Multiple properties separate with commas: ```css .card { transition: box-shadow 0.2s ease, transform 0.2s ease; } .card:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.15); transform: translateY(-4px); } ``` `transition: all 0.3s` technically works. But when you add a property later and it starts animating unexpectedly, you'll spend time figuring out why. List the properties explicitly. Easing options: `ease` starts fast and slows down (default), `linear` keeps constant speed, `ease-out` decelerates toward the end. For UI interactions, `ease-out` feels the most natural because it mirrors how physical objects stop. `cubic-bezier()` gives you exact control over the curve. ### animation + @keyframes: scripted motion `@keyframes` describes motion as a sequence of snapshots. `from/to` is identical to `0%/100%`, but you can add percentage stops at any point: ```css @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.08); } 100% { transform: scale(1); } } .badge { animation: pulse 1.5s ease-in-out infinite; } ``` The key `animation` sub-properties: - `animation-name` - which `@keyframes` block to use - `animation-duration` - how long one cycle takes - `animation-timing-function` - same easing options as transition - `animation-delay` - wait before the first play - `animation-iteration-count` - `1`, `3`, or `infinite` - `animation-direction` - `normal`, `reverse`, `alternate` (plays forward then backward) - `animation-fill-mode` - what state the element holds before or after playing `animation-fill-mode: forwards` is worth memorizing on its own. Without it, an element snaps back to its original state the moment the animation ends. That breaks most fade-in implementations. ### What to animate for performance Browsers paint the page in layers. `transform` and `opacity` changes happen on the compositor thread, which runs separately and never touches layout. Every other property (`width`, `height`, `padding`, `left`, `top`) forces the browser to recalculate positions or repaint. ```css /* triggers reflow every frame - slow */ .bad { transition: width 0.3s ease; } /* stays on compositor thread - fast */ .good { transition: transform 0.3s ease; } ``` To animate an element growing, use `transform: scaleX()` or `scaleY()` instead of `width` or `height`. For sliding elements in or out, `transform: translateX()` beats `left` every time. `will-change: transform` hints to the browser to promote an element to its own compositor layer before the animation starts. From experience in production: adding it blindly to everything is a common over-optimization. Profile first, then add it only where you actually see jank - each promoted layer takes GPU memory. ### Common mistakes **Animating layout properties.** Changing `height` or `width` in a loop drops frames. Use `transform: scaleY()` for expanding elements instead. **`transition: all`.** Works, but causes unexpected animations on unrelated properties. List properties explicitly. **Missing `animation-fill-mode: forwards`.** An element fades in beautifully, then snaps back to `opacity: 0`. Add `forwards` and the final keyframe state persists. **Using `@keyframes` for hover effects.** A hover change is exactly two states. That is what `transition` exists for. `@keyframes` earns its place when you need three or more states, or when the animation runs without any user interaction. **No `prefers-reduced-motion` support.** Some users have vestibular conditions where motion causes real discomfort. Small effort, real impact: ```css @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } ``` ### Follow-up questions **Q:** Which CSS properties are safe to animate for performance? **A:** `transform` and `opacity`. They run on the compositor thread without triggering layout or repaint. Properties like `width`, `height`, `top`, and `left` cause reflow on every frame. **Q:** What does `animation-fill-mode: forwards` do? **A:** It tells the element to keep the styles from the last keyframe after the animation finishes. Without it, the element reverts to its original styles the moment the animation ends. **Q:** Can you run multiple animations on one element? **A:** Yes, with a comma-separated list: `animation: fadeIn 0.3s ease, pulse 1s ease-in-out 0.3s infinite`. Each animation gets its own timing and they overlap independently. **Q:** When does `transition` not work? **A:** On properties with no calculable midpoint. You cannot transition `display: none` to `display: block` because there is no middle state. For show/hide effects, transition `opacity` combined with `visibility`, or use `transform: scale(0)` to scale down to nothing. **Q:** What is the difference between `animation-direction: alternate` and writing two separate keyframe sequences? **A:** `alternate` reverses automatically on odd-numbered iterations using the same easing. Two separate sequences give you independent control over forward and reverse curves - useful when you want slow ease-in going out and a fast snap coming back. ## Examples ### Button hover with transition ```css .btn { background: #3b82f6; color: white; padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; /* two properties, each with its own timing */ transition: background 0.25s ease, transform 0.15s ease; } .btn:hover { background: #2563eb; transform: scale(1.03); } .btn:active { transform: scale(0.97); /* pressed feedback */ } ``` `background` takes 0.25s while `transform` responds in 0.15s. That slight difference feels more natural than locking both to the same speed - the scale snaps crisply while the color follows. ### Loading spinner with animation ```css @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .spinner { width: 24px; height: 24px; border: 3px solid #e5e7eb; border-top-color: #3b82f6; border-radius: 50%; animation: spin 0.75s linear infinite; } ``` `linear` is the right call here. A spinner with `ease` speeds up and slows down on every loop, which looks like it is struggling. Constant speed is what you want.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.