CSS guide

CSS Gradient Guide: Linear, Radial and Conic

How linear-gradient(), radial-gradient() and conic-gradient() work, from angles and color stops to hard stops, layering, text gradients and modern color interpolation.

Updated · 9 min read

CSS gradients are generated images. They are drawn by the browser at any size, cost no HTTP request, and can be used anywhere an image is accepted: background-image, border-image, mask-image and list-style-image. There are three shapes — linear, radial and conic — each with a repeating variant.

Because a gradient is an image, not a color, it can't be used with background-color or color. Use background or background-image.

Linear gradients

A linear gradient transitions colors along a straight line.

/* Default direction is top to bottom (180deg) */
background-image: linear-gradient(#4f46e5, #06b6d4);

/* Keyword direction */
background-image: linear-gradient(to right, #4f46e5, #06b6d4);

/* Corner keyword: angle adapts to the element's aspect ratio */
background-image: linear-gradient(to bottom right, #4f46e5, #06b6d4);

/* Explicit angle: 0deg points up, angles go clockwise */
background-image: linear-gradient(135deg, #4f46e5, #06b6d4);

Angles vs keywords

0deg points to the top, 90deg to the right, 180deg to the bottom. Side keywords like to right are exact equivalents of 90deg. Corner keywords are different: to bottom right is not always 135deg. The browser computes the angle so the corners themselves get the start and end colors, which means the angle changes with the element's width and height. Use a corner keyword when you want the colors pinned to corners; use a fixed angle when you want the same slope on every card regardless of size.

Color stops and hints

Each color can take a position. Without positions, stops are spread evenly. With them, you control where each color is fully reached:

/* Hold #4f46e5 until 20%, blend to #06b6d4 by 80% */
background-image: linear-gradient(90deg, #4f46e5 20%, #06b6d4 80%);

/* Two positions on one stop = a solid band */
background-image: linear-gradient(90deg, #4f46e5, #a855f7 40% 60%, #06b6d4);

/* A color hint: move the midpoint of the transition to 25% */
background-image: linear-gradient(90deg, #4f46e5, 25%, #06b6d4);

A color hint is a bare position between two stops. It sets where the halfway color appears, which skews the transition without adding a new color.

Hard stops

When two adjacent stops share the same position, there is no transition, just a crisp edge. This is how stripes, split backgrounds and progress bars are made without extra elements:

/* Half-and-half split */
background-image: linear-gradient(90deg, #0f172a 50%, #f8fafc 50%);

/* Progress bar at 65% */
background-image: linear-gradient(90deg, #22c55e 65%, #e2e8f0 0);

The 0 in the second example is a shortcut: a stop position smaller than the previous one is clamped to the previous position, which guarantees a hard edge.

Radial gradients

Radial gradients radiate from a center point. The syntax is radial-gradient(shape size at position, stops).

/* Ellipse that fills to the farthest corner (the default) */
background-image: radial-gradient(#fde68a, #f59e0b);

/* Circle centered at the top left */
background-image: radial-gradient(circle at top left, #fde68a, transparent 60%);

/* Explicit size: a 200px circle */
background-image: radial-gradient(circle 200px at 50% 30%, #fff 0, #fff0 100%);

/* Size keywords: closest-side, closest-corner, farthest-side, farthest-corner */
background-image: radial-gradient(circle closest-side, #6366f1, #1e1b4b);

Radial gradients are useful for spotlights, vignettes and soft “glow” blobs behind hero content. Fading to transparent lets them sit on top of other backgrounds.

Conic gradients

Conic gradients sweep colors around a center point, like a color wheel. Stops are given in angles or percentages of the full turn.

/* Color wheel */
background-image: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);

/* Pie chart with hard stops */
background-image: conic-gradient(#4f46e5 0 40%, #06b6d4 0 75%, #e2e8f0 0);
border-radius: 50%;

/* Start angle and center */
background-image: conic-gradient(from 90deg at 30% 50%, #f43f5e, #fb923c);

Pie charts and donut charts are the classic use case; add a radial mask or an inner element for the hole. For anything a screen reader user needs to understand, provide the data as text too — a gradient carries no semantic meaning.

Repeating gradients

repeating-linear-gradient(), repeating-radial-gradient() and repeating-conic-gradient() tile the stop list. The last stop's position defines the length of one repetition.

/* Diagonal warning stripes, 20px each */
background-image: repeating-linear-gradient(
  45deg,
  #facc15 0 20px,
  #1f2937 20px 40px
);

/* Checkerboard */
background-image: repeating-conic-gradient(#e5e7eb 0 25%, #fff 0 50%);
background-size: 24px 24px;

Layering gradients

background-image accepts a comma-separated list. The first layer is drawn on top. Combining gradients with transparency creates rich backgrounds without image files:

.hero {
  background:
    radial-gradient(circle at 20% 20%, rgb(99 102 241 / 0.35), transparent 50%),
    radial-gradient(circle at 80% 0%, rgb(6 182 212 / 0.3), transparent 45%),
    linear-gradient(180deg, #0f172a, #020617);
}

Gradients also layer over photos: a dark linear gradient on top of a url() image improves the legibility of overlaid text.

Gradient borders

border-color doesn't accept gradients, but there are two reliable workarounds. The simplest is border-image, which works well for square corners but ignores border-radius:

.box {
  border: 3px solid;
  border-image: linear-gradient(90deg, #4f46e5, #db2777) 1;
}

For rounded corners, use two background layers with different clip boxes: a solid fill clipped to the padding box on top, and the gradient clipped to the border box underneath. The transparent border lets the gradient show through only at the edges:

.card {
  border: 2px solid transparent;
  border-radius: 12px;
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(135deg, #4f46e5, #06b6d4) border-box;
}

The inner layer must be an image too — hence linear-gradient(#fff, #fff) rather than a plain color, since only the final background layer may be a color.

Gradients as masks and fades

Gradients are also useful when nobody sees them as gradients. A mask-image with a gradient fades content out — for example, a truncated article preview or a horizontally scrolling row that hints there is more to see:

.preview {
  max-height: 12rem;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, #000 60%, transparent);
}

.scroller {
  mask-image: linear-gradient(90deg, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
}

In a mask only the alpha channel matters, so the colors are irrelevant; #000 means “visible” and transparent means “hidden”. Because the fade is applied to the element itself, it works on any background, unlike the older technique of overlaying a white-to-transparent gradient.

Gradient text

To fill text with a gradient, paint the background and clip it to the glyphs:

.gradient-text {
  color: #4f46e5; /* fallback if clipping is unsupported */
  background-image: linear-gradient(90deg, #4f46e5, #db2777);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

Keep the solid color fallback. If clipping fails, or in forced-colors mode, the text is still readable. Also check that both ends of the gradient meet contrast requirements against the background, since the lightest part of the text sets the effective contrast.

Interpolation color spaces

By default gradients between legacy sRGB colors (hex, rgb(), hsl()) are interpolated in sRGB, which can produce a muddy gray band — blue to yellow is the classic example. Modern browsers let you pick the interpolation space after the direction:

/* Perceptually even blend, no gray dead zone */
background-image: linear-gradient(in oklch 90deg, #2563eb, #facc15);

/* oklab: smooth and avoids hue shifts */
background-image: linear-gradient(in oklab to right, #2563eb, #facc15);

/* Polar spaces can choose the hue path */
background-image: conic-gradient(in oklch longer hue, oklch(70% 0.2 0), oklch(70% 0.2 0));

oklab is a good default for two-color blends. oklch keeps chroma high through the middle, which looks vivid but can travel through unexpected hues; shorter hue (the default) and longer hue control which way around the wheel it goes. Browsers that don't support the syntax drop the whole declaration, so put a plain gradient first as a fallback:

background-image: linear-gradient(90deg, #2563eb, #facc15);
background-image: linear-gradient(in oklab 90deg, #2563eb, #facc15);

See the MDN reference for color-interpolation-method for the full list of spaces. To get your brand colors into the right format, use the color converter.

Accessibility and contrast

  • Measure text contrast against the lightest (for dark text, the darkest) point the text overlaps, not the average.
  • Always set a background-color fallback close to the gradient's dominant tone so content stays readable if the image layer fails or is overridden by user styles.
  • Avoid conveying meaning only by gradient color (for example, a red-to-green status bar without a label).
  • Animated gradients should respect prefers-reduced-motion.

Performance

Static gradients are cheap; the browser rasterises them once per size. Costs appear when gradients are repainted every frame:

  • Animating background-position on a huge gradient or changing stop colors in an animation triggers a repaint each frame. Prefer animating transform or opacity of a pseudo-element that holds the gradient.
  • Very large, full-viewport gradients with many layers and background-attachment: fixed can be slow to scroll on mobile.
  • Subtle banding in long, low-contrast gradients can be reduced with an extra midpoint stop or an oklab interpolation, rather than a noise image.

Common mistakes

  • Using background-color: linear-gradient(…) — it is invalid and silently ignored.
  • Expecting to bottom right to equal 135deg on non-square elements.
  • Forgetting that a later background shorthand resets an earlier background-image.
  • Fading to the keyword transparent in old engines produced gray edges; modern browsers interpolate in premultiplied alpha, so it is safe today.

Build it visually

Writing stop lists by hand is fine for two colors but tedious for layered designs. The CSS gradient generator lets you drag stops, switch between linear, radial and conic, and copy the finished CSS. If you're pairing a gradient with depth effects, the box shadow guide and the glassmorphism generator are natural next steps.