CSS and web

SVG gradients: linear, radial, strokes, text and masks

SVG has its own gradient system, older than CSS gradients and able to do things they cannot: colour a stroke, fill a word, share one gradient across many shapes, and fade anything with a mask.

GradientlyVerified Gradiently account··5 min read
Cover: Cold Salon · GR·4AB2·SW

The short version

  • An SVG gradient is defined once as a linearGradient or radialGradient element with stop children, given an id, and applied with fill or stroke set to url(#id).
  • By default SVG gradient coordinates use objectBoundingBox units, where 0 and 1 are the edges of the shape being painted.
  • gradientUnits="userSpaceOnUse" places the gradient in the drawing's own coordinates, which lets one gradient span several shapes and fixes gradients on perfectly straight lines.
  • spreadMethod decides what happens beyond the gradient's ends: pad holds the end colours, reflect mirrors the blend and repeat restarts it.
  • An SVG mask uses brightness, so a white to black gradient inside a mask fades whatever it is applied to.
On this page

An SVG gradient is a paint you define once and apply to any shape, line or piece of text in an SVG. You write a <linearGradient> or <radialGradient> element inside <defs>, give it <stop> children for its colours and an id, then set a shape's fill or stroke to url(#id). Unlike a CSS background, it can colour a stroke or a single word, and it scales with the drawing.

html
<svg viewBox="0 0 200 120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="dusk" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#1e1b4b" />
      <stop offset="0.55" stop-color="#7c3aed" />
      <stop offset="1" stop-color="#f472b6" />
    </linearGradient>
  </defs>
  <rect width="200" height="120" rx="16" fill="url(#dusk)" />
</svg>
A diagonal gradient on a rounded rectangle. x1, y1, x2 and y2 draw the gradient's line from top left to bottom right.
The same blend, as CSSlinear-gradient(135deg, #1e1b4b 0%, #7c3aed 55%, #f472b6 100%)
The SVG above and this CSS gradient match on a square. On a rectangle, the SVG version stretches with the shape; see gradientUnits below.

linearGradient and its stops

x1, y1, x2 and y2 set the start and end of the gradient's line. Each <stop> takes an offset from 0 to 1 (or 0% to 100%), a stop-color and an optional stop-opacity. stop-color is also a CSS property, so you can theme gradients from a stylesheet, for example stop { stop-color: var(--accent); }.

AttributeDefaultWhat it does
x1 y1 x2 y20 0 1 0, left to rightStart and end points of the gradient line
gradientUnitsobjectBoundingBoxWhether coordinates are relative to the shape or to the drawing
spreadMethodpadWhat happens beyond the ends: pad, reflect or repeat
gradientTransformnoneRotate, scale or skew the gradient, e.g. rotate(30)
hrefnoneInherit stops and settings from another gradient
The main attributes of linearGradient. radialGradient shares all but the first row.

href saves repetition. Define your stops once in a base gradient, then create variations that point at it and change only the direction or units. The MDN linearGradient reference covers every attribute.

radialGradient: centre, radius and focal point

A radial gradient takes a centre (cx, cy) and a radius (r), all defaulting to 0.5, so it fills the shape from the middle. It also has something CSS lacks: a separate focal point (fx, fy) where the first colour starts. Moving the focal point off-centre makes a sphere look lit from one side.

html
<radialGradient id="orb" cx="0.5" cy="0.5" r="0.5" fx="0.32" fy="0.28">
  <stop offset="0" stop-color="#e0f2fe" />
  <stop offset="0.45" stop-color="#0ea5e9" />
  <stop offset="1" stop-color="#082f49" />
</radialGradient>

<circle cx="60" cy="60" r="50" fill="url(#orb)" />
A focal point up and to the left turns a flat circle into a glossy sphere.
Lit sphere, approximated in CSSradial-gradient(circle at 32% 28%, #e0f2fe, #0ea5e9 35%, #082f49 80%)
CSS can move the centre but not split centre and focus, so this is only an approximation of the SVG orb. Compare CSS radial gradients.

gradientUnits: objectBoundingBox or userSpaceOnUse

With the default objectBoundingBox, 0 and 1 mean the edges of whichever shape is being painted, so every shape gets the whole gradient, stretched to fit. With userSpaceOnUse, coordinates are in the SVG's own units, so the gradient stays put and shapes reveal whichever part of it they cover. That is how a row of bars can share one continuous gradient.

objectBoundingBox

  • Coordinates from 0 to 1 across each shape
  • Every shape shows the full gradient
  • The gradient stretches with the shape's proportions
  • Fails on a perfectly horizontal or vertical line

userSpaceOnUse

  • Coordinates in the drawing's own units
  • Shapes reveal their slice of one gradient
  • Angles stay true whatever the shape
  • Works on straight lines and thin strokes

Gradients on strokes and text

stroke="url(#id)" paints outlines, which is how gradient icons, progress rings and chart lines are drawn. On <text>, fill="url(#id)" colours the letters and the words stay selectable and searchable. Add a flat colour after the URL, such as fill="url(#dusk) #7c3aed", and it is used if the gradient cannot be found.

html
<svg viewBox="0 0 320 120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="line" gradientUnits="userSpaceOnUse" x1="20" y1="0" x2="300" y2="0">
      <stop offset="0" stop-color="#22d3ee" />
      <stop offset="1" stop-color="#a855f7" />
    </linearGradient>
  </defs>
  <path d="M20 90 C 90 20, 160 110, 300 30" fill="none" stroke="url(#line)" stroke-width="6" stroke-linecap="round" />
  <text x="20" y="115" font-size="20" font-weight="700" fill="url(#line) #7c3aed">Growth</text>
</svg>
One gradient in drawing units, shared by a curve and a word. Both run cyan to purple across the same horizontal span.

For gradient lettering in HTML rather than SVG, gradient text in CSS is usually simpler. Reach for SVG text when the words are part of an illustration or logo, or need to follow a path.

spreadMethod: pad, reflect and repeat

When the gradient's line is shorter than the shape, spreadMethod decides what fills the rest. pad holds the end colours, reflect mirrors the blend back and forth, and repeat starts it again with a hard edge. Here each gradient runs from 30% to 70% of the width.

Teal to sand with the three spread methods, reproduced in CSS so you can compare them side by side.

Fading with SVG masks

A mask uses brightness: white areas show what is masked, black areas hide it, and greys are in between. So a white to black gradient inside a <mask> fades any shape or image smoothly to nothing, which is how you soften the edge of a photo or make a chart line fade out at its start.

html
<defs>
  <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0.4" stop-color="#fff" />
    <stop offset="1" stop-color="#000" />
  </linearGradient>
  <mask id="soft-bottom">
    <rect width="100%" height="100%" fill="url(#fade)" />
  </mask>
</defs>

<image href="photo.jpg" width="100%" height="100%" mask="url(#soft-bottom)" />
The photo is fully visible at the top and fades out over its lower 60%.

For HTML elements, CSS mask-image: linear-gradient(#000 40%, transparent) does the same job, using alpha rather than brightness. The mask technique also powers transparent CSS gradient borders.

Avoid

  • Reusing the same gradient id in two inline SVGs on one page
  • Hiding a sprite of gradient definitions with display: none
  • Default units on straight lines
  • Very long, smooth, dark gradients with no texture

Do

  • Unique ids, or one shared definitions sprite
  • Hide sprites with zero width and height instead
  • userSpaceOnUse for strokes and shared gradients
  • Add grain to large fades, see CSS noise texture

Questions people ask

How do I add a gradient to an SVG?

Define a <linearGradient> or <radialGradient> with <stop> children and an id inside <defs>, then set a shape's fill or stroke to url(#id).

Why is my SVG gradient stroke not showing on a line?

A straight horizontal or vertical line has a zero-size bounding box, so the default objectBoundingBox units fail. Use gradientUnits="userSpaceOnUse" with real coordinates.

How do I rotate an SVG gradient?

Change x1, y1, x2 and y2, or add gradientTransform="rotate(45 0.5 0.5)" to rotate around the centre of the bounding box.

Can I change SVG gradient colours with CSS?

Yes. stop-color and stop-opacity are CSS properties, so rules such as stop { stop-color: var(--accent); } work on inline SVG.

Why did my SVG gradient disappear when I hid the SVG?

Definitions inside an SVG with display: none may not render. Hide the sprite with zero width and height, or absolute positioning, instead.

Share this guide

Written by GradientlyVerified Gradiently account

The team behind Gradiently, a design tool built around Marks: living gradients that make everything you design look like yours.

See our profile