If you've only ever shipped linear-gradient(to right, blue, red), you're using about one-third of what CSS gradients can do. There are only three functions, and the mental model for each is small. Here's the whole thing in one read.
The one fact that makes everything click
A gradient is not an image file. Per MDN, a <gradient> is a special kind of <image> that the browser generates at render time. So it:
- scales to any size without blurring (it's drawn, not sampled)
- weighs zero bytes (no file, no HTTP request)
- edits with one hex value instead of a re-export
That's why gradients exist. Everything below is just how to steer them.
Three functions, three shapes
| Function | Shape | Reach for it when |
|---|---|---|
linear-gradient() |
straight line along an axis | backgrounds, buttons, overlays |
radial-gradient() |
outward from a center point | spotlights, glows, vignettes |
conic-gradient() |
rotational sweep around a center | pie charts, color wheels, spinners |
Linear - the workhorse
background: linear-gradient(to right, #ff7e5f, #feb47b); /* orange→peach */
background: linear-gradient(135deg, #6366f1 0%, #ec4899 100%); /* indigo→pink */
Direction is an angle (45deg) or a keyword (to right, to top right). Stops are a color plus an optional position.
Radial - when the fade should read as light
background: radial-gradient(circle, #fff, #000);
Shape (circle vs ellipse), center position, and sizing keywords (closest-side, farthest-corner) do the work. Because the fade tracks distance from a point, radial reads as depth - perfect for glows, vignettes, and spotlight effects.
Conic - the one most people skip
background: conic-gradient(#f00 0 25%, #0f0 25% 50%, #00f 50% 75%, #ff0 75%);
Conic sweeps by angle, not distance. That single difference makes it the right tool for pie charts and color wheels - effects that were hacky before conic-gradient() shipped.
The rule that surprises everyone
Two color stops at the same position don't fade - they make a hard edge:
background: linear-gradient(to right, #000 50%, #fff 50%);
/* clean half-and-half split, no image file */
That's the entire mechanism behind striped and banded backgrounds. Space the stops and you get stripes; ring them with repeating-radial-gradient() and you get concentric circles.
/* Diagonal stripes, pure CSS */
background: repeating-linear-gradient(45deg, #6366f1 0 20px, #ec4899 20px 40px);
Stacking: the overlay pattern you'll use in every hero
Image properties accept a comma-separated list, and the browser stacks them front to back (first listed on top). Put a transparent dark layer over a colorful base and text on top stays readable:
background:
linear-gradient(rgba(0, 0, 0, 0.4), transparent),
/* tint on top */ linear-gradient(to right, #6366f1, #ec4899); /* base gradient */
Reordering the list reorders the stack. This is how mesh backgrounds and texture overlays get built from pure CSS.
Gradients aren't only backgrounds (an <image> goes anywhere)
Because a gradient is an <image>, it works in every property that accepts one:
/* Gradient text */
background: linear-gradient(to right, #6366f1, #ec4899);
-webkit-background-clip: text;
background-clip: text;
color: transparent; /* keep text readable if the gradient fails */
/* Transparent overlay (fade to readable darkness) */
background: linear-gradient(rgba(0, 0, 0, 0.5), transparent);
border-image and mask-image accept gradients too. border-color does not - for gradient borders you use border-image or a wrapper element. (Accessibility note for background-clip: text: the underlay text must remain legible if the degradation path runs; don't let the words disappear.)
Support and paint cost - the two gotchas
- Support. Linear and radial have been unprefixed in every major browser for 10+ years; caniuse shows near-universal support. Conic arrived later - verify it if you target old browsers. Ignore vendor prefixes unless you need them for legacy.
-
Paint cost. A static gradient paints once and costs nothing measurable. A gradient that animates, covers a huge surface, or stacks many layers can tax the paint step. Rule of thumb: gradients beat background images on load time, and lose to solid colors on paint time. If you animate one, you can't transition gradient values directly between keyframes - interpolate
background-positionon an oversized gradient instead, or register a@propertycustom property.
The 5-step recipe
- Pick the shape:
linear-gradient(),radial-gradient(), orconic-gradient(). - Set direction (angle/keyword) or shape+position first.
- List two or more color stops - color plus optional position (
0%,20px,50%). - Assign to
backgroundorbackground-image. - Preview across sizes, nudge stop positions until it lands.
When you want syntax in seconds instead of by hand, a visual CSS gradient generator writes the code for you - pick colors, drag stops, copy.
Three shapes, positioned stops, comma-separated stacks, watch the paint cost when you animate. That's the whole mental model. The spec that nails it all down is CSS Images Module Level 4 if you ever want the precise definition of how interpolation behaves.
Cross-posted from ToolSura.
Top comments (0)