CSS Mesh Gradient Technique

Build linear, radial, and conic CSS gradients with a visual editor. Drag color stops, pick presets, and copy ready-to-use CSS, Tailwind, or custom property output.

ZERO UPLOAD · ALL LOCAL
  1. Choose a gradient type with the Linear / Radial / Conic toggle, or click a preset to load a starting point.
  2. Click anywhere on the gradient track to add a color stop, then drag it left or right to reposition it.
  3. Click a handle to select it, then type any CSS color format (HEX, RGB, HSL, or OKLCH) into the color field, or use the swatch to open the browser color picker.
  4. Drag the angle dial to rotate a linear gradient or set the starting angle for a conic gradient. For radial and conic types, set the center position with the X and Y inputs.
  5. Choose CSS, Tailwind, or Vars in the output panel and click Copy to grab the result.

What this page covers

  • 3 to 6 gradient layers fewer looks like a flat two-tone blend, more adds cost without visible improvement
  • Transparent outer stops each radial-gradient layer must fade to transparent at its edge for layers below to show through
Gradient Type
Presets
Color Stops
0 50 100
Angle
135° deg
Results
 

CSS Mesh Gradient Technique with layered radial gradients

Layering multiple radial gradients with transparent edges creates the soft, blended look of a mesh gradient using nothing but standard CSS background-image values. Each layer contributes a colored blob at a specific position, and the layers blend where they overlap. No special CSS feature is required: comma-separated background-image values stack radial gradients from front to back.1

The key is transparency: each gradient layer uses rgba() or oklch() colors with alpha values below 1 for the outer stops, letting lower layers show through in the overlap regions.2 The result resembles the smooth multicolor mesh gradients from design tools like Figma, built entirely in CSS without SVG or canvas. Consequently, mesh gradients work in all modern browsers without polyfills. Building on this, adjusting the radial size and position of each layer controls how far each color blob extends and where the blended overlap regions appear on the element.

Layering multiple radial-gradient() values

CSS accepts comma-separated background-image values. Each value renders as a separate layer, with the first value on top and subsequent values below. For a mesh effect, each layer is a radial-gradient() positioned at a different point with a color that fades to transparent at its edges. The number of layers determines the complexity of the mesh: three layers produce a simple blend, while five or six layers create the rich, organic look associated with design tool mesh gradients.

A three-blob mesh uses three layers: radial-gradient(circle at 30% 40%, oklch(0.75 0.2 250 / 0.8) 0%, transparent 60%), followed by two more layers at different positions with different colors. The browser composites the layers using the normal blend mode by default.1 Consequently, overlapping regions show additive blending through the alpha channel: where a blue blob at 0.8 opacity overlaps a red blob at 0.7 opacity, the result is a purple region. Controlling each blob's alpha at the center stop adjusts how saturated the overlap regions appear. The number of layers determines the complexity of the mesh: three layers produce a simple blend, while five or six layers create the rich, organic look associated with design tool mesh gradients. Positioning the blobs at slightly irregular intervals rather than on a strict grid prevents the pattern from reading as geometric.

Using transparent stops to reveal lower layers

The outer stop of each radial gradient must use a transparent or low-alpha color for the mesh effect to work. A gradient from a solid color to transparent(oklch(0.7 0.2 250)) fades to nothing at its outer edge, revealing the layers below.2 Without transparency in the outer stop, each layer covers all layers beneath it completely and the mesh effect disappears. Choosing a base background color that matches the average hue of the gradient blobs prevents the uncovered regions from appearing as a mismatched background that clashes with the overall mesh composition.

Adjusting blend coverage

The percentage position of the transparent stop controls how far each blob extends before fading. Moving the outer stop from 60% to 80% makes the blob cover more of the element before fading to transparent. Moving it to 40% makes a smaller, more concentrated blob. Pair the stop position with an alpha value below 0.5 at the center to create an even softer blend where the overlap regions between blobs sit at similar perceived brightness, preventing any one blob from appearing to sit perceptually on top of the others in the stack.

Yet very small blobs with an outer stop below 30% may leave large uncolored regions between blobs that break the mesh illusion and reveal the underlying background in unflattering patches. Furthermore, the base background color of the element shows through in regions not covered by any blob, so set a background-color that complements the gradient blobs to control the mesh's overall tone. For dark-mode mesh gradients, reducing the chroma of each blob to 0.05 or below and keeping lightness between 0.12 and 0.25 produces a subtle atmospheric texture that reads as depth rather than as a set of colored circles floating on a dark surface.

Adjusting radial size and position for intersection blends

Each layer's radial size and center position determines where blobs overlap. Positioning two blobs within 20% to 30% of each other on both axes creates a visible overlap region where the colors blend. Positioning them farther apart produces isolated color pools with minimal blending. Using oklch() colors with consistent lightness values across all blobs produces a mesh where no single color dominates perceptually, keeping the overall composition balanced.

Building a mesh grid

A systematic approach places blobs at grid positions: 25% 25%, 75% 25%, 25% 75%, and 75% 75% for a four-blob mesh. Each blob uses a different hue and covers a radius large enough to overlap with its neighbors, typically 40% to 60% of the element size. Starting with a four-blob grid lets you validate that the color relationships read as intended before layering in additional complexity, and adjusting the radius of every blob by the same percentage keeps the overlap ratios consistent as the mesh grows or shrinks across breakpoints.

The overlap regions at the grid intersections show blended colors from two or more layers. Adding a fifth blob at the center pulls the mesh together visually and eliminates any uncolored region near the element midpoint. Using oklch() colors with consistent lightness values across all blobs produces a mesh where no single color dominates perceptually. For hero sections that need the mesh to feel organic rather than grid-based, offsetting each blob from its grid position by a random small percentage breaks the rigid symmetry and produces a more natural distribution.

Controlling mesh blob positions with CSS custom properties

CSS custom properties make mesh gradient blob parameters configurable without editing the gradient function directly. Declaring custom properties for each blob's x position, y position, and size at the component level lets you adjust each blob through a single variable block. Applying all three parameters as custom properties reduces the multi-layer gradient to a readable template where the circle center and outer radius reference the variables.

Animating blob positions with @property creates a flowing mesh that shifts color pools smoothly over time.3 Registering each position property as type number (representing a percentage) allows @keyframes to interpolate between positions without the discrete snap behavior that untyped custom properties produce. A four-blob mesh with independently animating positions produces a slow, aurora-like surface motion with no JavaScript.

Limiting animation to prefers-reduced-motion off

Wrapping the @property animation in @media (prefers-reduced-motion: no-preference) respects the user's system-level motion preference.4 Users who have enabled reduced motion see the static mesh gradient, while users without that preference see the animated version. This pattern applies to any CSS gradient animation and is a baseline accessibility requirement for production deployments. Combining this media query with the @property registration ensures that only browsers supporting both features run the animation, providing a clean fallback to the static gradient in older browsers and respecting user preferences simultaneously.

When to use this

Use mesh gradients for hero backgrounds, card surfaces, and decorative panels where a single-direction gradient feels too simple. On small elements the blending area is often too tight to read as a mesh rather than a smeared color, so see where your mesh blobs actually overlap at the size you plan to ship before committing to the effect.

Examples

Hero section background with four-color mesh

Place four radial blobs at 25% 25%, 75% 25%, 25% 75%, 75% 75%. Use oklch colors with hues 90 degrees apart for adjacent blobs. Set the outer stop to transparent at 60% for each layer. Add a base background-color matching the darkest gradient tone.

Card surface with a subtle two-color mesh

Use two overlapping blobs, one at 30% 30% and one at 70% 70%. Keep alpha values at 0.3 to 0.5 for a muted effect that does not compete with card content. The blending midpoint between the blobs creates a natural focal point for the card layout.

Dark-mode mesh gradient for a sidebar panel

Use oklch colors with lightness below 0.25 and chroma below 0.1 for dark surface blobs. High-chroma blobs look neon on dark backgrounds rather than atmospheric. Reduce chroma to 0.05 to 0.08 for subtle depth without color noise.

Sources
  1. 1.

    W3C, "CSS Backgrounds and Borders Module Level 3," w3.org, July 2024. https://www.w3.org/TR/css-backgrounds-3/#background-image

  2. 2.

    CSS-Tricks, "radial-gradient()," css-tricks.com, July 2025. https://css-tricks.com/almanac/functions/r/radial-gradient/

  3. 3.

    Mozilla Developer Network, "@property," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/@property

  4. 4.

    Mozilla Developer Network, "prefers-reduced-motion," developer.mozilla.org, June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion

FAQ