Stockio

Animate CSS Gradients Smoothly With @property

Animate gradient angles and stops with typed CSS custom properties, then add reliable fallbacks, reduced-motion support, and practical paint-performance checks.

By Aiko Tanaka

Motion Designer ·

On this page

A gradient is an image generated from several inputs: colors, stops, an angle, and sometimes a center or shape. Animating the entire background-image value does not generally interpolate between arbitrary gradient declarations. A more controlled approach is to animate one typed input and let the browser rebuild the gradient from that changing value.

Start with a gradient worth keeping still

Build a static background with the gradient generator. Choose a small number of colors, copy the CSS, and preview it behind the actual content. The resting result must work before motion enters the design. A moving background cannot rescue a gradient whose brightest region makes labels disappear.

Choose a single animation variable: perhaps an angle rotating behind a badge, or a color stop drifting across a decorative separator. Moving several parameters at once makes debugging harder and often produces unnecessary visual activity. For a first implementation, use two colors and one angle.

Separate the decorative layer from readable content. If a heading sits over a gradient, place it on a stable opaque surface or verify every reachable background state. Use the contrast checker to check representative foreground/background pairs, including the lightest and darkest combinations the animation produces. Endpoint checks alone can miss a problematic intermediate blend.

Register an interpolable value

Unregistered custom properties behave like token sequences rather than typed angles or lengths. Their animation is generally discrete, so a variable can jump between values instead of moving smoothly. The @property registration tells the browser what kind of value it should interpolate.

A registration supplies a syntax descriptor, an inheritance decision, and, for this syntax, a valid initial value. An angle such as 0deg is computationally independent and works as an initial value. Avoid using a value such as 1em as the initial value for a registered length, because it depends on another computed value.

Read the MDN @property reference when choosing syntax. An angle registration should receive angles, not arbitrary strings. A percentage registration can drive a stop position, while a color registration can interpolate a color input. Match the grammar to the smallest useful parameter rather than allowing everything.

Names are shared across the document, so use a component-specific prefix. A generic variable called angle is easy for another component to reuse accidentally. Explicit inheritance also matters: a decorative component usually benefits from inherits: false, keeping its animated value from unexpectedly flowing into descendants.

Animate the angle with a static fallback

This example leaves the base gradient intact everywhere. Motion is opt-in through a class that JavaScript adds only when the registration API is available and the operating system has not requested reduced motion. CSS repeats the preference guard to handle preference changes safely.

@property --halo-angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}

.halo {
--halo-angle: 0deg;
background: linear-gradient(
  var(--halo-angle), #2447c7, #c23f8b
);
}

@media (prefers-reduced-motion: no-preference) {
.gradient-motion .halo {
  animation: halo-turn 12s linear infinite;
}
}

@keyframes halo-turn {
from { --halo-angle: 0deg; }
to { --halo-angle: 360deg; }
}
const canRegister =
"CSS" in window && "registerProperty" in CSS;
const motionAllowed = window.matchMedia(
"(prefers-reduced-motion: no-preference)"
).matches;

if (canRegister && motionAllowed) {
document.documentElement.classList.add("gradient-motion");
}

The feature check is a practical enhancement gate for modern engines; test the actual stylesheet in your supported browsers as well. A custom-property support query alone would not prove that typed registration works. If JavaScript is unavailable, the static background remains complete and legible.

A full angle turn returns the image to an equivalent orientation, making this loop visually continuous. That does not mean any pair of gradient endpoints will loop cleanly. A stop moving from ten to ninety percent will jump when it resets unless the design hides the reset or uses alternating direction.

Control stops, pacing, and visual emphasis

For a moving stop, register a percentage and use that variable at a valid stop position. Keep neighboring stops ordered unless crossing them is intentional. When a later stop is placed before an earlier one, CSS gradient stop fixup can create a hard edge rather than the smooth wave you expected.

Use linear pacing for a seamless rotation. Ease-in-out is more useful when a decorative patch should drift to one side and return, because it reduces abrupt velocity changes at the ends. Neither choice makes the motion physically meaningful by itself; match the rhythm to the role of the surface.

Do not mistake a twelve-second loop for an accessibility guarantee. Slow, large-area movement can still distract or cause discomfort. Consider a single short entrance animation, a user-controlled preview, or an animated state limited to a loading task. Automatically moving content may also require pause controls depending on its behavior and context.

Keep motion out of error messages and reading surfaces unless it communicates something necessary. The micro-interaction guide offers a useful framing: the animation should reinforce a recognizable state change, not compete with the task. A decorative highlight that never stops has a very different attention cost from a brief confirmation.

Measure painting and verify fallbacks

Typed interpolation does not imply compositor-only animation. Changing gradient inputs commonly requires repainting the background. A small badge can be inexpensive while the same animation across a full viewport becomes costly. Compare both on a modest device, not only a development laptop.

Use paint flashing and a performance recording to see the affected area. The web.dev animation guide explains why transform and opacity are generally preferable when they can express the same effect. If rotating a separate decorative layer gives an acceptable result, compare that approach, while accounting for clipping and its different visual geometry.

Avoid stacking multiple animated gradients, filters, and backdrop blur before measuring. Isolate one effect, record a baseline, and add complexity only when the result justifies the cost. Large layers also have memory costs even when their animation can be composited.

Test progressive enhancement explicitly: disable JavaScript, remove the motion class, enable reduced motion, and inspect a browser without registration support. Every case should retain the intended static design. Consult MDN on CSS custom properties for variable fallback behavior, which is distinct from feature detection. Finally, verify the chosen angle and stop names do not collide with other components after stylesheets are combined.

Key takeaways

  • Build a readable static gradient before animating any parameter.
  • Register angles, percentages, or colors with the correct syntax.
  • Animate a single input first and check loop continuity.
  • Treat gradient animation as potential paint work, not a free effect.
  • Keep unsupported and reduced-motion experiences complete without animation.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Motion & Animation
Motion & Animation

10 Best Motion Design Tools for Beginners

Compare ten approachable motion design tools for simple titles, interface animations, and short videos. Find an entry point that matches your budget, device, and creative goals.

Includes: GradientsAiko TanakaAiko Tanaka
Motion & Animation

Skeleton Loading Animation: CSS Shimmer Done Right

Create skeleton loaders that reserve real space, use restrained shimmer, respect reduced motion, and hand off cleanly to loaded content without hiding errors or controls.

Includes: GradientsAiko TanakaAiko Tanaka
Motion & Animation

CSS Scroll-Driven Animations With Scroll Timelines

Create progressive CSS scroll-driven effects with scroll() and view(), preserve readable fallbacks, and test timeline ranges without hijacking normal scrolling.

Includes: GradientsAiko TanakaAiko Tanaka
Typography & Colour

10 Best Gradient Generators and Collections

Explore ten gradient generators and libraries for backgrounds, illustrations, and interface details, with notes on how each tool helps and what to check before using its output.

Includes: GradientsMateo FernándezMateo Fernández
AI for Design & UX

AI User Interview Analysis Without Losing Nuance

Use AI to organise interview evidence without outsourcing interpretation. Preserve source references, challenge tidy themes and build findings that remain traceable to participant behaviour.

Includes: GradientsMaya LindqvistMaya Lindqvist
AI for Design & UX

AI Motion Design Tools for Micro-Interactions

Use AI to prototype purposeful interface motion, then check reduced-motion behaviour, interruptions and rendering cost before shipping micro-interactions.

Includes: GradientsMaya LindqvistMaya Lindqvist