CSS Animation Properties
What You Learn From This Page
- How animation properties control the playback of a named
@keyframessequence. - How name, duration, timing, delay, iteration, direction, fill mode, and play state work.
- How positive and negative delays affect the animation timeline.
- How reverse directions change endpoints, timing functions, and fill behavior.
- How the animation shorthand is parsed and how it resets omitted longhands.
- How comma-separated lists align when multiple animations run together.
- How to pause, resume, restart, cancel, and observe animation lifecycle events.
- How to design animation properties for accessibility, performance, and stable application state.
Introduction
An @keyframes rule describes the property values that form an animation sequence. Animation properties describe how that sequence plays on a particular element. The same keyframes can run once or forever, quickly or slowly, forward or backward, immediately or after a delay. They can apply endpoint styles outside active playback, pause at the current position, or run alongside other named animations.
This separation is important in real projects. A reusable fade-in sequence may be appropriate for a tooltip, notification, and modal, but each component can use a different duration and delay. A rotation sequence becomes a useful spinner only when it receives a nonzero duration, linear timing, and an infinite iteration count. Keyframes answer what changes; animation properties answer how the browser schedules and samples those changes.
The properties also form a timeline model. There can be a before phase, an optional delay, an active interval containing one or more iterations, and an after phase. Direction and fill mode determine which keyframe values are relevant in each phase. Understanding that model prevents common surprises such as invisible content during delays, snapping after completion, a reverse animation filling from the wrong assumed endpoint, or a shorthand silently resetting a longhand.
The Core Animation Properties
The primary playback longhands are animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, and animation-play-state. The animation shorthand combines them.
.element {
animation-name: fade-in;
animation-duration: 400ms;
animation-timing-function: ease-out;
animation-delay: 0ms;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: both;
animation-play-state: running;
}
Writing longhands makes every decision visible and helps isolate list-matching problems. The shorthand is usually more compact for component code, but it must be read with its parsing and reset behavior in mind.
animation-name
animation-name selects one or more @keyframes rules. The identifier must resolve to the intended name. A missing or mismatched definition means the selected sequence cannot produce the expected effect.
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.message {
animation-name: fade-in;
}
The initial value is none, which selects no keyframe animation. Setting animation-name: none is a direct way to disable playback in a responsive or reduced-motion override. Names should express intent, such as modal-enter or loading-spin, instead of implementation order such as animation-3.
An animation name alone is not enough to create visible playback because the initial duration is zero. It connects the element to a sequence, while the other properties determine whether and how that sequence occupies time.
Multiple animation-name Values
A comma-separated name list selects multiple animations. Other animation longhands also accept lists, and values align by position.
.illustration {
animation-name: fade-in, float;
animation-duration: 400ms, 3s;
animation-timing-function: ease-out, ease-in-out;
animation-iteration-count: 1, infinite;
}
The first set describes fade-in; the second describes float. If both effects write the same property, such as transform, they do not automatically concatenate their transform functions under ordinary replacement behavior. Coordinate the values in one sequence, apply effects to nested wrapper elements, or deliberately use advanced composition only when requirements and browser support justify it.
animation-duration
animation-duration defines the length of one iteration. It accepts seconds or milliseconds, and its initial value is 0s. A zero-duration animation may still participate in lifecycle and fill behavior, but no ordinary visible interpolation occupies time.
.notification {
animation-duration: 240ms;
}
.decorative-orbit {
animation-duration: 6s;
}
Duration should match the distance, complexity, and urgency of the effect. Direct interface feedback usually needs a short duration. Larger movement may need enough time for the eye to follow it, but users should not wait through decorative playback before they can continue working. Test on representative devices instead of choosing a number only from a design mockup.
Iteration count multiplies active duration. A two-second animation with three iterations has approximately six seconds of active playback, excluding a positive delay. Paused time extends wall-clock completion because the animation timeline stops advancing while paused.
animation-timing-function
The timing function maps elapsed time to progress within keyframe segments. Its initial value is ease. Other common choices include linear, ease-in, ease-out, ease-in-out, cubic-bezier(), steps(), and linear().
.spinner {
animation-timing-function: linear;
}
.dialog {
animation-timing-function: ease-out;
}
Linear timing suits constant rotation and genuinely uniform progress. Ease-out gives entrances immediate visible response and a gentle finish. Ease-in can suit selected exits, while ease-in-out works for reversible movement. A curve does not change total duration; it redistributes progress within that duration.
With intermediate keyframes, timing is evaluated between offsets. A timing function declared inside a keyframe controls the segment that begins at that keyframe. This allows a bounce to use one curve while rising and another while falling.
animation-delay
animation-delay offsets the start of the active interval. Its initial value is 0s. A positive delay creates a waiting period before active playback.
.card {
animation-name: card-enter;
animation-duration: 320ms;
animation-delay: 150ms;
}
During that delay, underlying styles normally apply. A backwards or both fill mode can apply the relevant starting keyframe instead. This distinction matters when the starting keyframe is transparent: without fill, content may show normally during the delay and then abruptly become transparent when the active interval begins.
Delays should support sequencing or interaction intent. A five-second delay on direct feedback makes the interface appear broken. If content is useful immediately, do not conceal it merely to stage a decorative entrance.
Negative Animation Delays
A negative delay starts the animation as if that amount of time had already elapsed. It does not make the browser wait a negative duration. For a one-second infinite rotation, -250ms begins approximately one quarter of the way through the cycle.
.dot:nth-child(1) { animation-delay: 0ms; }
.dot:nth-child(2) { animation-delay: -200ms; }
.dot:nth-child(3) { animation-delay: -400ms; }
Negative delays are useful for distributing repeated loaders or decorative loops across phases. With finite animations, a negative delay can skip early iterations or place the effect near completion immediately. Direction, iteration count, and fill mode still participate, so test the actual timeline instead of assuming the first keyframe will appear.
animation-iteration-count
Iteration count specifies how many cycles run. Its initial value is 1. Positive numbers can be whole or fractional, and infinite continues until the animation is removed, canceled, or otherwise stopped.
.success-mark {
animation-iteration-count: 2;
}
.spinner {
animation-iteration-count: infinite;
}
A value of 2.5 plays two complete iterations and half of the third. The final sampled position depends on direction and fill behavior. Infinite movement should have a clear purpose, such as indicating loading. Repeated pulsing on ordinary cards and buttons creates noise, consumes resources, and competes with the user's task.
animation-direction
Direction controls how each iteration traverses keyframe offsets. The values are normal, reverse, alternate, and alternate-reverse.
| Value | Iteration Behavior |
|---|---|
normal | Every iteration runs from 0% to 100% |
reverse | Every iteration runs from 100% to 0% |
alternate | Odd iterations run forward; even iterations run backward |
alternate-reverse | Odd iterations run backward; even iterations run forward |
Alternate direction is useful for floating, oscillating, and back-and-forth motion because it avoids a jump from the final value directly to the first value at each cycle boundary.
.icon {
animation:
float 2s ease-in-out infinite alternate;
}
Reverse playback affects more than offset order. Easing is reversed appropriately for the playback direction, and the relevant start and end keyframes used by fill mode change. Do not assume that forwards means the 100-percent block regardless of direction.
The Animation Timeline and Fill Phases
It is useful to divide an animation into before, active, and after phases. A positive delay normally belongs to the before phase. Duration multiplied by iteration count forms the active interval. Time after the active interval is the after phase. Fill mode determines whether the keyframe effect applies during the before and after phases.
This model separates two ideas that are frequently confused. Direction controls how the sequence plays during active iterations. Fill mode controls whether an endpoint effect is visible outside active playback. The keyword forwards does not tell the animation to play forward, and backwards does not tell it to play backward.
animation-fill-mode: none
none is the initial fill mode. Underlying element styles apply before the active interval and after it completes. If those styles differ from the keyframe endpoints, the element may appear to jump when animation begins or ends.
.message {
opacity: 1;
animation: fade-out 300ms ease-in;
animation-fill-mode: none;
}
After this fade completes, underlying opacity returns to one. That may be correct for a temporary emphasis effect, but it is incorrect if the application expects the message to stay hidden.
animation-fill-mode: forwards
forwards retains the effect value from the animation's relevant ending point after the active interval. Which endpoint is relevant depends on direction and the final iteration.
.message {
animation: fade-out 300ms ease-in forwards;
}
The message remains visually transparent after completion, but it can still occupy layout, receive focus, or intercept pointer interaction. Fill mode is not complete component state management. Stable hidden state should be represented by classes, attributes, visibility, inertness, DOM lifecycle, and accessibility semantics appropriate to the component.
animation-fill-mode: backwards and both
backwards applies the relevant starting keyframe during the before phase, including a positive delay. This prevents an entrance animation from showing its final state while it waits.
.panel {
animation:
panel-enter 300ms ease-out 500ms backwards;
}
both combines backwards behavior before active playback with forwards behavior afterward. It is common for one-time entrances because the first keyframe applies during delay and the last effect remains after completion. Even so, align the normal component styles with the intended stable state so removing the animation does not produce a surprise.
animation-play-state
Play state accepts running and paused. Its initial value is running. Pausing freezes playback at the current timeline position; resuming continues from that position rather than restarting.
.demo {
animation: orbit 4s linear infinite;
animation-play-state: paused;
}
.demo.is-playing {
animation-play-state: running;
}
Hover-based pause can help a visual demonstration, but hover is not available to every user. If pausing is required for usability, provide an explicit keyboard-operable button and communicate its current state. Pausing an animation does not necessarily pause the application process represented by that animation.
The animation Shorthand
The shorthand expresses one or more complete animation definitions. A readable conventional order is name, duration, timing function, delay, iteration count, direction, fill mode, and play state.
.panel {
animation:
panel-enter
300ms
ease-out
100ms
1
normal
both
running;
}
Most components use a shorter form because omitted values receive their initials.
.panel {
animation: panel-enter 300ms ease-out both;
}
.loader {
animation: spin 800ms linear infinite;
}
The shorthand resets omitted animation longhands. If a rule previously sets animation-fill-mode: both and a later rule writes animation: panel-enter 300ms, fill mode returns to none. Treat shorthand as a complete playback definition rather than an additive update.
Parsing Duration and Delay
Duration and delay both use time values. Within one shorthand item, the first time is duration and the second time is delay.
.element {
animation: fade-in 500ms ease 1s both;
}
This animation lasts 500 milliseconds after waiting one second. Duration cannot be negative, while delay can be negative. Keeping a consistent order helps reviewers distinguish timing values without reconstructing the grammar.
Names That Resemble Keywords
The shorthand contains keywords for timing, direction, fill, play state, and iteration. An animation name that resembles one of these values can make parsing or human interpretation difficult. Names such as reverse, running, or infinite should be avoided for keyframe rules.
Place a clear custom name consistently in the declaration and use intent-based identifiers. When a generated name is unavoidable, longhands remove ambiguity and make debugging easier.
Multiple Animation Shorthands
Separate complete animation definitions with commas. Each item owns its playback settings.
.illustration {
animation:
fade-in 400ms ease-out both,
float 3s ease-in-out 400ms infinite alternate;
}
The entrance finishes while the float continues. Keeping settings together is clearer than maintaining several differently sized longhand lists. It also makes it easier to remove one effect without disturbing the positional relationship among all the lists.
How Longhand Lists Match
When longhand lists have different lengths, CSS repeats values from shorter lists as needed and ignores unused values beyond the number of animation names. This is valid but easy to misread.
.element {
animation-name: fade-in, float, color-cycle;
animation-duration: 300ms, 2s;
animation-timing-function: ease-out;
}
Here the duration list repeats to cover the third name, and the single timing function applies across the list. Prefer matched lists or complete shorthand items unless repetition is deliberate and documented.
Cascade, Inheritance, and Component Ownership
Animation properties are not inherited by default. A parent animation does not automatically cause every descendant to run the same keyframes. Descendants may still appear to move because they are painted inside a transformed parent, but their computed animation properties remain independent. This distinction matters when pausing a component: setting play state on the parent does not pause separately animated children unless selectors include them.
Normal cascade rules decide which animation declarations win. A component rule, state class, media query, utility class, or shorthand can override earlier longhands. Keep ownership clear: the component should define its normal playback, state selectors should activate or replace it intentionally, and accessibility overrides should come from a predictable layer. Excessive specificity makes stopping or simplifying motion harder.
.notification {
animation: none;
}
.notification[data-state="entering"] {
animation:
notification-enter 240ms ease-out both;
}
@media (prefers-reduced-motion: reduce) {
.notification[data-state="entering"] {
animation: none;
}
}
This pattern ties playback to an explicit lifecycle state while leaving the stable component free of an animation. It also gives reduced motion a clear final override.
Configuring Animation with Custom Properties
Custom properties can expose controlled animation parameters without duplicating a complete shorthand. A design system can provide duration and easing tokens while each component selects an appropriate keyframe sequence.
:root {
--motion-duration-fast: 140ms;
--motion-duration-standard: 240ms;
--motion-ease-enter: cubic-bezier(0, 0, 0.2, 1);
}
.popover {
--popover-delay: 0ms;
animation:
popover-enter
var(--motion-duration-standard)
var(--motion-ease-enter)
var(--popover-delay)
both;
}
Tokens improve consistency, but unrestricted component variables can create unexpected values. Document valid ranges and preserve sensible fallbacks. For staggered content, an index variable can calculate delay; cap the index or delay when collections may become large so the final item does not wait excessively.
Newer Animation Controls and Progressive Enhancement
Modern CSS extends the core model with features such as animation-composition and scroll-driven animation timelines. Composition can influence how an animation effect combines with an underlying value, while timeline and range properties can connect progress to scrolling or view visibility instead of ordinary document time. These features solve different problems from the eight classic playback longhands.
Use them as progressive enhancements after checking the browser support required by the project. Keep essential content and component state correct when an advanced property is ignored. Feature queries can isolate an enhancement, but support testing must include the complete property and behavior rather than assuming that parsing one value guarantees every desired interaction.
.reading-progress {
animation: progress-fill 1s linear both;
}
@supports (animation-timeline: scroll()) {
.reading-progress {
animation-timeline: scroll();
}
}
A time-based fallback should be chosen carefully because simulated time may misrepresent real reading progress. When no truthful fallback exists, a stable nonanimated indicator is better than misleading motion.
Staggering with Delay
Staggered entrances can communicate ordering, but a large cumulative delay hides useful content. A custom property scales the pattern without duplicating full declarations.
.card {
--index: 0;
animation: card-enter 320ms ease-out both;
animation-delay: calc(var(--index) * 60ms);
}
.card:nth-child(2) { --index: 1; }
.card:nth-child(3) { --index: 2; }
.card:nth-child(4) { --index: 3; }
Keep the interval and maximum total sequence modest. Under reduced motion, remove the delay as well as the movement; otherwise later items may remain in a backwards-filled hidden state before appearing.
Restarting and Canceling Animations
Changing play state from paused to running resumes an existing animation; it does not restart it. Reapplying an identical class may also leave the computed animation unchanged, so no new effect is created. Applications sometimes remove and reapply a class, change the animation name, or use the Web Animations API when explicit restart control is required.
Removing the animation property or the element can cancel playback. Design cleanup code for cancellation as well as successful completion. Avoid forcing layout merely to restart a decorative effect unless measurement and requirements justify that cost.
Animation Events
JavaScript can observe animationstart, animationiteration, animationend, and animationcancel. Events expose the animation name, which is important when several effects run on one element.
element.addEventListener("animationend", (event) => {
if (event.animationName === "notification-exit") {
element.remove();
}
});
Essential application logic should not depend solely on a decorative animation ending. Reduced-motion overrides, DOM removal, cascade changes, and interruption can change the lifecycle. Filter events by name and provide a deterministic fallback for required cleanup.
Real-World Modal Entrance
@keyframes modal-enter {
from {
opacity: 0;
transform: scale(0.97);
}
to {
opacity: 1;
transform: scale(1);
}
}
.modal {
animation:
modal-enter 220ms ease-out both;
}
The animation properties produce a short one-time entrance and retain the ending effect. The modal's actual open state, focus placement, background inertness, and closing behavior must still be managed separately. Animation enhances the state change; it does not define modal semantics.
Real-World Loader and Floating Effect
A spinner combines short duration, linear timing, and infinite iteration. A decorative float uses ease-in-out, infinite iteration, and alternate direction.
.loader {
animation: spin 800ms linear infinite;
}
.decorative-icon {
animation:
float 2.5s ease-in-out infinite alternate;
}
The loader should stop when work ends and should have accessible status text. The decorative effect should be disabled or simplified when motion is reduced, and it should not compete with primary content.
Animation Properties and Application State
Fill mode, delay, and direction change presentation, not business state. A forwards-filled fade-out leaves an element transparent but does not automatically hide it from assistive technology, remove it from layout, or prevent interaction. A paused spinner does not mean a request is paused. A completed success pulse does not persist the success state.
Represent stable state through classes, attributes, DOM structure, and semantic properties. Use animation properties to describe the journey into, out of, or around that state. This separation keeps the interface correct when animations are disabled, interrupted, unsupported, or skipped.
Responsive and Visibility Considerations
Animation properties do not know whether a page-load entrance is currently visible in the viewport. An effect may complete while its element is offscreen or behind another view. When viewport-triggered playback matters, use appropriate application logic rather than a large arbitrary delay.
Responsive rules can change or disable an animation with animation-name: none or the shorthand. Test what the shorthand resets and ensure content does not remain hidden because its base styles expected backwards fill. Motion distance and duration should remain suitable at narrow widths, zoomed layouts, and localized content lengths.
Accessibility and Reduced Motion
Large slides, zooms, spinning, repeated bouncing, and constant movement can cause discomfort. Use prefers-reduced-motion to remove nonessential animation or replace spatial movement with a brief low-motion change.
@media (prefers-reduced-motion: reduce) {
.animated,
.loader,
.decorative-icon {
animation: none;
}
}
Because animation is a shorthand, this override resets every animation longhand. Ensure the stable nonanimated CSS leaves content visible and usable. If a loading spinner disappears, retain accessible loading text. Do not rely on motion as the only error, success, selection, or focus indicator, and avoid rapid flashing effects.
Performance Considerations
Playback settings alone do not determine rendering cost. The properties inside keyframes, affected element size, number of simultaneous effects, and duration of repeated work are more important. Transform and opacity are frequently efficient for visual movement; width, height, margin, padding, top, and left may require layout. Large filters and shadows can be paint-heavy.
An infinite transform on one small loader may be reasonable. The same effect on hundreds of cards can consume CPU, GPU, memory, and battery while distracting users. Stop offscreen or obsolete effects when practical and profile frame timing on representative devices.
will-change is not another animation property and should not be applied globally. Use it only when performance measurement demonstrates a benefit, and remove it when the optimization is no longer needed.
Default Values Reference
| Property | Initial Value | Purpose |
|---|---|---|
animation-name | none | Selects keyframes |
animation-duration | 0s | Sets one iteration length |
animation-timing-function | ease | Maps time to segment progress |
animation-delay | 0s | Offsets active playback |
animation-iteration-count | 1 | Sets repetition count |
animation-direction | normal | Controls offset traversal |
animation-fill-mode | none | Controls before and after effects |
animation-play-state | running | Runs or pauses playback |
Common Mistakes and Better Approaches
| Mistake | Better Approach |
|---|---|
| Name is set but duration is omitted | Provide a meaningful nonzero duration |
| Animation name does not match keyframes | Use consistent intent-based identifiers |
| Infinite iteration is added to feedback | Run error and success effects a limited number of times |
forwards is confused with direction | Separate fill behavior from playback direction |
backwards is expected to reverse motion | Use direction for reversal and fill for delay styling |
| Long delay hides direct feedback | Use delay only for clear sequencing needs |
| Large stagger keeps content unavailable | Cap interval and total sequence time |
| Shorthand unexpectedly removes fill mode | Treat shorthand as a full reset |
| Multiple effects compete for transform | Combine values or use nested elements |
| Transparent forwards-filled content remains interactive | Manage actual state, focus, and lifecycle separately |
| Paused animation has no accessible resume control | Provide an explicit control when pausing matters |
| Reduced motion removes the only content reveal | Make stable content usable without animation |
Debugging Animation Properties
If an animation is not visible, inspect computed styles. Confirm that the name resolves, duration is greater than zero, iteration count is not zero, play state is running, and no later shorthand resets the settings. Check reduced-motion and responsive rules, positive or negative delays, and whether the animation completed before the element became visible.
If the ending snaps, compare fill mode with underlying styles. If direction appears wrong, inspect alternate parity and fractional iteration count. If several effects behave unexpectedly, expand shorthand values and verify comma-separated list alignment. Browser animation panels can replay timelines, slow playback, and expose keyframe segments.
Test interruption, pause and resume, rapid class changes, cancellation, DOM removal, background-tab behavior, and different viewport sizes. Production failures often occur around lifecycle boundaries rather than during one uninterrupted ideal run.
Common Interview Questions
What are the main CSS animation properties? They are name, duration, timing function, delay, iteration count, direction, fill mode, and play state, plus the shorthand.
What is the initial animation duration? It is 0s, so a name alone normally produces no visible interpolation.
How do you repeat an animation forever? Use animation-iteration-count: infinite.
What does alternate direction do? It runs odd iterations forward and even iterations backward.
What does forwards fill mode do? It retains the relevant ending keyframe effect after active playback.
What does backwards fill mode do? It applies the relevant starting keyframe effect during the before phase, including a positive delay.
Does pausing restart an animation? No. Resuming normally continues from the paused timeline position.
How are two time values parsed in the shorthand? The first is duration and the second is delay.
What does a negative delay do? It begins as though the animation timeline has already advanced by that amount.
Why should fill mode not represent application state? It changes presentation without automatically updating semantics, layout participation, focus, or business state.
Practical Review Checklist
- Use a clear keyframe name and a duration greater than zero.
- Choose timing that matches entrance, exit, continuous, or discrete motion.
- Use positive delay only for purposeful sequencing.
- Test negative delay with finite iterations and reverse directions.
- Use infinite iteration only for justified ongoing activity.
- Check alternate parity and fractional iteration endpoints.
- Select fill mode according to before and after timeline needs.
- Keep stable component state outside animation fill behavior.
- Provide accessible pause controls when users need control.
- Treat the shorthand as a reset of every animation longhand.
- Keep multiple-animation lists aligned and readable.
- Avoid competing animations that write the same property.
- Remove animation delays in reduced-motion overrides.
- Keep content visible and usable when animation is disabled.
- Profile the properties animated, not only playback settings.
- Stop unnecessary infinite effects when they are no longer visible.
- Handle animation cancellation as well as successful completion.
- Test computed styles, timeline phases, interruption, and responsive layouts.
Key Takeaway
CSS animation properties turn a keyframe definition into a scheduled effect. Name selects the sequence, duration gives one iteration time, timing functions shape progress, delay offsets the active interval, iteration count controls repetition, direction controls traversal, fill mode affects before and after phases, and play state pauses or resumes the timeline. The shorthand can express all of them but also resets every omitted longhand.
Use these controls as presentation, not as a substitute for real component state. Keep delays and repetition purposeful, understand reverse endpoints and fill phases, align multiple-animation lists carefully, and preserve content when motion is disabled. When accessibility, lifecycle, and rendering cost are considered together, animation properties provide predictable control without making the interface depend on animation to remain correct.