Skip to content

Radial Gradients

A radial gradient is a color ramp that expands from a center point. Instead of projecting pixels onto a straight line, the renderer measures each pixel's distance from the radial center, normalizes that distance through a circle or an ellipse, and samples the ordered stops at the matching radius.

In gradiente, a radial gradient is a typed model with shape, size, position, interpolation settings, stops, optional color hints, and a repeating flag. The same model can be transformed into CSS, Canvas 2D, Canvas WebGL, SVG, or a custom transformer target.

css
radial-gradient(circle at 35% 35% in oklch, #ff74f6 0%, #fb7655 45%, #405de6 100%)
Radial gradient exampleOff-center OKLCH radial glowradial-gradient(circle at 35% 35% in oklch, #ff74f6 0%, #fb7655 45%, #405de6 100%)
Preview loads when it reaches the viewport.

Every preview block on this page renders the same source gradient in four targets at once: CSS, Canvas 2D, Canvas WebGL, and SVG. The WebGL column is a snapshot generated through transformTo('canvas-webgl', gradient) so the page does not keep many live WebGL contexts open at the same time. Preview rendering is lazy-loaded as each example approaches the viewport.

gradiente integration

Use a radial gradient in your framework

The same gradiente model can be mounted in React, Vanilla JS, Vue, or Svelte. Each example parses the source string, converts it through transformTo('css'), and applies the result as a real background image.

ReactRadialGradientPreview.tsx

What A Radial Gradient Contains

The radial gradient model has five conceptual parts:

Function name`radial-gradient(...)` or `repeating-radial-gradient(...)`. The public instance type remains `radial-gradient`; repeating is stored as config.
Shape`circle` or `ellipse`. The default is `ellipse`.
SizeAn extent keyword such as `closest-side`, `closest-corner`, `farthest-side`, `farthest-corner`, or explicit length/percentage radii.
PositionA center point introduced by `at`, such as `at left top`, `at center`, or `at 25% 75%`.
Stop listColor stops, optional percentage positions, optional double positions, and color hints along the radius.

The model that gradiente stores is renderer-agnostic:

ts
type GradientRadialConfig = {
  shape: 'circle' | 'ellipse'
  size:
    | {
        kind: 'extent'
        value: 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner'
      }
    | {
        kind: 'explicit'
        x: GradientLengthPercentage
        y?: GradientLengthPercentage
      }
  position: GradientPosition
  interpolation: {
    colorSpace: GradientColorSpace
    hue?: GradientHueInterpolation
  }
  isRepeating?: boolean
}

Stop positions are stored as normalized numbers where 0 means the center and 1 means the resolved outer radius. The same shared stop model is used:

ts
type GradientRadialStop =
  | {
      type: 'color-stop'
      value: string
      position: number
    }
  | {
      type: 'color-hint'
      position: number
    }

Color values stay as strings so they can preserve author intent. Renderers convert and sample them only when they need concrete colors.

What gradiente Does

For radial-gradient, gradiente handles the work that usually gets scattered across parsers, UI code, serializers, and renderers:

  • Parses CSS-like radial strings into a GradientRadial instance.
  • Stores shape, size, center position, interpolation, stops, and repeating state.
  • Resolves default values from one constructor location.
  • Resolves missing stop positions.
  • Preserves color hints as first-class stop data.
  • Compacts double-position stops during serialization.
  • Normalizes repeated radial gradients through the same model.
  • Resolves concrete radii per renderer when a target area is known.
  • Transforms the same model to CSS, Canvas 2D, Canvas WebGL, and SVG.

Anatomy

The full syntax has one optional configuration item followed by a required stop list:

css
radial-gradient(
  [shape] [size] [at position] [in color-space [hue-mode hue]],
  color-stop-or-hint,
  color-stop-or-hint,
  ...
)

The first comma-separated item is treated as configuration only when it contains radial config tokens. Everything after the first comma belongs to the stop list.

css
radial-gradient(circle closest-side at 30% 35% in oklch, red 0%, 35%, blue 100%)
Radial gradient exampleShape, size, position, interpolation, color hint, and stopsradial-gradient(circle closest-side at 30% 35% in oklch, red 0%, 35%, blue 100%)
Preview loads when it reaches the viewport.

That example contains:

  • circle: the normalized distance field is circular.
  • closest-side: the outer radius touches the closest side of the paint box.
  • at 30% 35%: the center is placed near the upper-left area.
  • in oklch: colors are interpolated in OKLCH.
  • red 0%: the first color stop is placed at the center.
  • 35%: a color hint that moves the midpoint of the red-to-blue transition.
  • blue 100%: the final color stop is placed at the resolved outer radius.

Defaults

If radial config is omitted, gradiente uses the CSS-like default radial shape:

css
radial-gradient(red, blue)
Radial gradient exampleDefault radial gradientradial-gradient(red, blue)
Preview loads when it reaches the viewport.

The class defaults are:

txt
shape: "ellipse"
size.kind: "extent"
size.value: "farthest-corner"
position: center center
interpolation.colorSpace: "srgb"
isRepeating: false

Default values are omitted from toString(). That is why radial-gradient(ellipse farthest-corner at center in srgb, red, blue) can serialize to the compact radial-gradient(red, blue).

Shape

Shape controls the distance field used by the renderer.

circle keeps the x and y radii equal. It is useful for glows, spotlights, focus rings, circular masks, buttons, badges, and centered effects.

css
radial-gradient(circle, red, blue)
Radial gradient exampleCircle shaperadial-gradient(circle, red, blue)
Preview loads when it reaches the viewport.

ellipse allows different x and y radii. It is the default shape because it naturally fills rectangular boxes.

css
radial-gradient(ellipse 35% 70%, cyan, blue 60%, black)
Radial gradient exampleExplicit ellipse sizeradial-gradient(35% 70%, cyan 0%, blue 60%, black 100%)
Preview loads when it reaches the viewport.

When the shape is omitted, gradiente stores ellipse. When the shape is explicitly circle, the serializer keeps it because it changes the geometry.

Size

Size determines the resolved radius or radii. It can be keyword-based or explicit.

The extent keywords are:

`closest-side`The gradient reaches the closest side from the center.
`closest-corner`The gradient reaches the closest corner from the center.
`farthest-side`The gradient reaches the farthest side from the center.
`farthest-corner`The gradient reaches the farthest corner from the center. This is the default.

closest-side is compact and often useful for controlled local highlights.

css
radial-gradient(circle closest-side, red, blue)
Radial gradient exampleclosest-side extentradial-gradient(circle closest-side, red, blue)
Preview loads when it reaches the viewport.

closest-corner depends on both the center and the rectangular paint area.

css
radial-gradient(circle closest-corner at 25% 75%, #ff74f6, #405de6)
Radial gradient exampleclosest-corner extentradial-gradient(circle closest-corner at 25% 75%, #ff74f6, #405de6)
Preview loads when it reaches the viewport.

farthest-side can create broad fields that still stop before the farthest corner.

css
radial-gradient(circle farthest-side at left center, #ff74f6, #405de6)
Radial gradient examplefarthest-side extentradial-gradient(circle farthest-side at left center, #ff74f6, #405de6)
Preview loads when it reaches the viewport.

Explicit sizes use concrete radii. A circle uses one length value; an ellipse can use two length or percentage values.

css
radial-gradient(circle 70px at center, red, blue)
Radial gradient exampleExplicit circle radiusradial-gradient(circle 70px, red, blue)
Preview loads when it reaches the viewport.

For an explicit ellipse, the first value is the x radius and the second value is the y radius:

css
radial-gradient(35% 70%, cyan 0%, blue 60%, black 100%)

Position

Position moves the radial center. It always follows at.

Keyword positions use x/y keywords:

css
radial-gradient(circle at top left, red, blue)
Radial gradient exampleKeyword positionradial-gradient(circle at left top, red, blue)
Preview loads when it reaches the viewport.

gradiente normalizes keyword positions into x/y order. For example, at top left serializes as at left top.

Value positions use two length-percentage values:

css
radial-gradient(circle at 25% 75%, red, blue)
Radial gradient examplePercentage positionradial-gradient(circle at 25% 75%, red, blue)
Preview loads when it reaches the viewport.

The current radial parser intentionally keeps positions strict: keyword positions are keyword-only, and value positions require two length-percentage tokens. Mixed CSS forms such as left 20px top 10px are not part of this model yet.

Stop List

The stop list defines what colors appear along the radius. A practical radial gradient usually has at least two color stops.

If a color stop has no explicit position, gradiente resolves it from neighboring stops. The first unresolved color stop becomes 0%; the last unresolved color stop becomes 100%; unresolved stops between known positions are distributed evenly.

css
radial-gradient(circle, red 0%, yellow 40%, blue 100%)
Radial gradient examplePositioned color stopsradial-gradient(circle, red 0%, yellow 40%, blue 100%)
Preview loads when it reaches the viewport.

Color hints are bare percentages between two color stops. They do not create a new color stop. They move the perceived midpoint of the interpolation segment.

css
radial-gradient(circle, red 0%, 35%, blue 100%)
Radial gradient exampleColor hintradial-gradient(circle, red 0%, 35%, blue 100%)
Preview loads when it reaches the viewport.

Double-position stops create hard rings. A color written with two positions is stored as two adjacent color stops with the same color, then serialized back into the compact form when possible.

css
radial-gradient(circle, red 0% 35%, blue 35% 100%)
Radial gradient exampleDouble-position stopsradial-gradient(circle, red 0% 35%, blue 35% 100%)
Preview loads when it reaches the viewport.

Interpolation

Interpolation controls the path between colors. This matters for radial gradients because a small center area can amplify interpolation artifacts: a muddy midpoint or a hard transition can become very visible.

The default interpolation space is srgb.

css
radial-gradient(circle in srgb, red, blue)
Radial gradient examplesRGB interpolationradial-gradient(circle, red, blue)
Preview loads when it reaches the viewport.

Perceptual spaces such as oklab often produce smoother ramps.

css
radial-gradient(circle at 25% 75% in oklab, red, blue)
Radial gradient exampleOKLab interpolationradial-gradient(circle at 25% 75% in oklab, red, blue)
Preview loads when it reaches the viewport.

Polar color spaces can use hue interpolation modes. gradiente supports shorter, longer, increasing, and decreasing.

css
radial-gradient(in oklch longer hue, hsl(325, 64%, 54%), hsl(208, 94%, 47%))
Radial gradient exampleOKLCH longer hue interpolationradial-gradient(in oklch longer hue, hsl(325, 64%, 54%), hsl(208, 94%, 47%))
Preview loads when it reaches the viewport.

Supported color spaces are:

txt
oklab
lch
oklch
hsl
hwb
lab
srgb
srgb-linear
xyz
display-p3
a98-rgb
prophoto-rgb
rec2020

Repeating Radial Gradients

repeating-radial-gradient(...) uses the same internal gradient kind as radial-gradient(...). The prefix sets isRepeating: true in the config, while the instance type remains radial-gradient.

css
repeating-radial-gradient(circle at center, red 0%, blue 20%)
Radial gradient exampleRepeating radial gradientrepeating-radial-gradient(circle, red 0%, blue 20%)
Preview loads when it reaches the viewport.

Repeating radial gradients are useful for ripples, targets, rings, scan effects, halftone-like surfaces, and generated pattern systems.

Programmatic Construction

Most users should start with parse() because it gives you the same input shape people already know from CSS. When you need to build a gradient directly, use GradientRadial.

The constructor takes two parameters:

txt
new GradientRadial(stops, config?)

stops is required. config is optional and missing values are resolved from class defaults.

ts
import { GradientRadial } from 'gradiente'

const gradient = new GradientRadial(
  [
    {
      type: 'color-stop',
      value: '#ff74f6',
      position: 0,
    },
    {
      type: 'color-stop',
      value: '#405de6',
      position: 1,
    },
  ],
  {
    shape: 'circle',
    size: {
      kind: 'extent',
      value: 'closest-side',
    },
    position: {
      kind: 'values',
      x: {
        kind: 'percent',
        value: 35,
      },
      y: {
        kind: 'percent',
        value: 45,
      },
    },
    interpolation: {
      colorSpace: 'oklch',
    },
  },
)
Radial gradient exampleEquivalent constructor outputradial-gradient(circle closest-side at 35% 45% in oklch, #ff74f6, #405de6)
Preview loads when it reaches the viewport.

Transforming A Radial Gradient

Every renderer target receives the same source model. That is the main point of the Core API: parse once, transform many times.

ts
import { parse, transformTo } from 'gradiente'

const gradient = parse(
  'radial-gradient(ellipse 35% 70% at 35% 45% in oklch longer hue, #ff74f6, #405de6)'
)

const css = transformTo('css', gradient)
const canvas2d = transformTo('canvas-2d', gradient)
const webgl = transformTo('canvas-webgl', gradient)
const svg = transformTo('svg', gradient)
Radial gradient exampleRenderer transformer inputradial-gradient(35% 70% at 35% 45% in oklch longer hue, #ff74f6, #405de6)
Preview loads when it reaches the viewport.

The transformer outputs have different shapes:

`css`A CSS background string.
`canvas-2d`A paint object with `draw(ctx, width, height)`.
`canvas-webgl`A paint object with `draw(canvas, width, height)`.
`svg`An SVG paint server payload with `defs`, `url`, and serialized SVG data.

Normalization

Use format() before storing user input. It parses the string into the internal model and serializes it back to the canonical gradiente string.

ts
import { format } from 'gradiente'

const input = 'radial-gradient(circle closest-side at 35% 45% in oklch, #ff74f6 0%, 42%, #405de6 100%)'
const normalized = format(input)
Radial gradient exampleFormatted user inputradial-gradient(circle closest-side at 35% 45% in oklch, #ff74f6 0%, 42%, #405de6 100%)
Preview loads when it reaches the viewport.

Normalization is useful when users type gradients manually, when editor state is saved, or when generated gradients need stable output for tests and snapshots.

Practical Checklist

Use this order when building or validating a radial gradient:

  1. Choose a shape: circle for equal radii, ellipse for rectangular fields.
  2. Choose a size: an extent keyword for CSS-like behavior, explicit radii for controlled geometry.
  3. Choose a position with at when the center should move away from the default center.
  4. Choose interpolation: srgb for CSS parity, oklab or oklch for smoother ramps.
  5. Add at least two color stops for useful visual output.
  6. Add explicit stop positions when rings or glow sizes must survive editing.
  7. Use color hints when the transition midpoint needs to move.
  8. Use double-position stops when you need hard rings.
  9. Use format() before storing user input.
  10. Use transformTo() for renderer output instead of hand-converting the string.