SVG gradients: linear and radial, for fill and stroke

An SVG gradient is defined once with linearGradient or radialGradient, then used as a fill or stroke by its id. Direction, stops, transparency and fixes.

Published

To fill an SVG shape with a gradient, define a <linearGradient> or <radialGradient> element with an id, put two or more <stop> colours inside it, and refer to it from the shape with fill="url(#id)". The same reference works for stroke. This is a complete file:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" viewBox="0 0 200 100">
  <defs>
    <linearGradient id="sunset">
      <stop offset="0" stop-color="gold"/>
      <stop offset="1" stop-color="crimson"/>
    </linearGradient>
  </defs>
  <rect width="200" height="100" fill="url(#sunset)"/>
</svg>

The rectangle runs from gold at its left edge to crimson at its right. The gradient sits in <defs>, the place for things that are defined but not drawn until something uses them. The shorter examples below are fragments: each belongs inside an <svg> element like this one.

Stops

Each <stop> fixes a colour at a point along the gradient.

AttributeMeaningDefault
offsetWhere the stop sits, from 0 (start) to 1 (end), or 0% to 100%0
stop-colorThe colour at that pointblack
stop-opacityHow solid the colour is there, 0 to 11

Colours blend evenly between one stop and the next. Before the first stop and after the last, the colour stays flat. List the stops in rising order of offset.

Two stops at the same offset give a hard edge with no blend. This fills the left half navy and the right half white:

<linearGradient id="halves">
  <stop offset="0.5" stop-color="navy"/>
  <stop offset="0.5" stop-color="white"/>
</linearGradient>

Direction of a linear gradient

A linear gradient runs along a line from the point x1,y1 to the point x2,y2. By default those numbers are fractions of the shape’s bounding box, where 0,0 is its top-left corner and 1,1 its bottom-right. The defaults are x1="0" y1="0" x2="1" y2="0": left to right.

DirectionAttributes to set
Left to rightNone
Right to leftx1="1" x2="0"
Top to bottomx2="0" y2="1"
Bottom to topx2="0" y1="1"
Top-left to bottom-righty2="1"

Note the x2="0" in the vertical rows. x2 is 1 unless changed, so setting only y2="1" gives a diagonal.

The other way to turn a gradient is gradientTransform. gradientTransform="rotate(90)" turns the default left-to-right gradient into a top-to-bottom one. To turn about the middle of the shape, give the centre: rotate(45 0.5 0.5).

Because the coordinates are fractions of the bounding box, a diagonal is corner to corner whatever the shape’s proportions. Only on a square shape is that 45 degrees. For an exact angle on a wide shape, switch to real coordinates, as described under strokes below.

Radial gradients

<radialGradient id="glow">
  <stop offset="0" stop-color="white"/>
  <stop offset="1" stop-color="steelblue"/>
</radialGradient>
<circle cx="50" cy="50" r="40" fill="url(#glow)"/>

A radial gradient spreads from a centre outwards: here white in the middle of the circle, steel blue at its edge. Its attributes:

AttributeMeaningDefault
cx, cyCentre of the outer circle, where offset 1 falls50% each
rRadius of that circle50%
fx, fyThe focal point, where offset 0 fallsSame as cx, cy

Moving the focal point off centre, for example fx="0.3" fy="0.3", pushes the bright spot up and to the left, which makes a disc look like a lit ball. On a shape that is not square, the default gradient is stretched into an ellipse to fit the box.

Fading to transparent

Set stop-opacity="0" on a stop and keep its colour the same as its neighbour:

<linearGradient id="fade">
  <stop offset="0" stop-color="crimson"/>
  <stop offset="1" stop-color="crimson" stop-opacity="0"/>
</linearGradient>

Using stop-color="transparent" for the second stop tends to look dirty in the middle, because transparent is transparent black and the colour blends towards black on its way out.

Gradients on a stroke

<circle cx="50" cy="50" r="40" fill="none" stroke="url(#sunset)" stroke-width="8"/>

The gradient is laid across the whole shape like a sheet, and the stroke shows the part of the sheet it covers. It does not follow the line round its curves: SVG has no gradient that runs along a path.

One case fails. A perfectly horizontal or vertical straight line has a bounding box with no height or no width, so a gradient measured in fractions of that box cannot be worked out, and the line is not painted. The fix is gradientUnits="userSpaceOnUse", which makes x1, y1, x2 and y2 ordinary coordinates in the drawing:

<linearGradient id="along" gradientUnits="userSpaceOnUse" x1="10" y1="0" x2="190" y2="0">
  <stop offset="0" stop-color="gold"/>
  <stop offset="1" stop-color="crimson"/>
</linearGradient>
<line x1="10" y1="50" x2="190" y2="50" stroke="url(#along)" stroke-width="6"/>

With userSpaceOnUse, one gradient can also run unbroken across several shapes, since it no longer restarts in each shape’s own box.

Repeating a gradient

spreadMethod says what happens beyond the ends of the gradient line. pad, the default, continues the end colours. repeat starts again from the first stop. reflect runs back and forth. They only show when the gradient line is shorter than the shape, for example x2="0.25", which with repeat gives four bands.

Changing a gradient with CSS

For an SVG that is inline in an HTML page, CSS can restyle the stops:

#sunset stop:first-child { stop-color: teal; }

CSS functions such as linear-gradient() make images, not paints, and cannot be used as a fill. For an SVG in an <img> or a CSS background, page CSS cannot reach the stops at all: see changing SVG colour with CSS. The gradient itself still shows there, provided it is defined inside the same file.

Gradients and cutting machines

A blade or a pen has no use for a gradient, and cutting software may not accept a file that has one. Cricut Design Space lists gradients among the unsupported items in an uploaded SVG, because it sorts shapes into layers by flat colour. Before uploading, replace each gradient with one colour. Uploading an SVG to Cricut Design Space lists the other things it refuses.

For print or screen use from other software, SVG to PNG turns the drawing, gradients included, into pixels.

Common problems

What you seeCauseFix
The shape disappearsThe name in url(#...) matches no id, often a typing slip or a difference in capitalsMake the two match exactly
A straight line with a gradient stroke is missingIts bounding box has no width or no heightgradientUnits="userSpaceOnUse"
One flat colourOnly one stop, or offsets above 1, such as 50 where 50% or 0.5 was meant: they all count as 1Give two stops with offsets between 0 and 1
Two SVGs in one page share a gradientBoth define the same id, and the first one winsGive each a different id
The gradient goes when its SVG is hiddenDefinitions kept in an inline SVG with display: none are not used by some browsersHide that SVG with width="0" height="0" and position: absolute
A diagonal is not at 45 degreesCoordinates are fractions of a box that is not squareuserSpaceOnUse with real coordinates
The fade looks greyA transparent stopSame colour, stop-opacity="0"
The cutting program reports unsupported itemsGradients are not flat colourRefill with flat colours

Questions

Can SVG make a conic or angular gradient? Not with an element of its own. SVG defines linear and radial gradients only.

Can text have a gradient? Yes. fill="url(#id)" works on <text> as on any shape, and the box it is measured against is the whole text element.

Where should the gradient go in the file? Anywhere inside the same SVG, by convention in <defs> near the top. It can be used by any number of shapes.

How do the other fill and stroke settings work? See SVG fill and stroke. The SVG viewer draws code as it is typed, which is the quickest way to try stops and directions.