SVG pattern: fill a shape with a repeating tile

The SVG pattern element repeats a small tile to fill or stroke a shape. How width, height and patternUnits set the tile, with dots, stripes, grid and checks.

Published

A <pattern> is a small drawing, the tile, that SVG repeats across and down to cover a shape. Define it once inside <defs> with an id, then use it as a paint: fill="url(#id)" or stroke="url(#id)".

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse">
      <circle cx="10" cy="10" r="4" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#dots)"/>
</svg>

The tile is 20 units square with one dot in the middle. The rectangle is 200 by 100, so it shows ten dots across and five down.

The parts of a pattern

AttributeMeaningDefault
idThe name the shape refers toNone
width, heightThe size of one tile. Required: with either at zero, nothing is drawn0
x, yWhere the first tile starts0
patternUnitsWhat x, y, width and height are measured inobjectBoundingBox
patternContentUnitsWhat the shapes inside the tile are measured inuserSpaceOnUse
patternTransformA transform applied to the whole pattern: rotate, scale, skewNone
viewBoxA coordinate system for the tile’s contents, scaled to fit the tileNone

A pattern draws nothing by itself. It appears only where a shape uses it.

patternUnits: the setting that causes the trouble

The two units attributes have opposite defaults, and that is why a first pattern so often comes out wrong.

  • patternUnits="userSpaceOnUse" measures the tile in the same units as the rest of the drawing. width="20" is a tile 20 units wide, whatever the shape. A bigger shape shows more tiles. This is what most people expect a pattern to do.
  • patternUnits="objectBoundingBox", the default, measures the tile as a fraction of the shape being filled. width="0.25" is a quarter of the shape’s width, so every shape gets exactly four tiles across, large or small.

The shapes inside the tile are still in ordinary units by default. So under the default settings the tile grows with the shape while the dot inside stays the same size:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="quarters" width="0.25" height="0.5">
      <circle cx="10" cy="10" r="8" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#quarters)"/>
</svg>

Here each tile is a quarter of the rectangle wide and half as tall, so 50 by 50 units, and there are four across and two down. The dot keeps its radius of 8 and sits in the corner of each tile.

The mistake to avoid is writing width="20" height="20" and leaving patternUnits out. That asks for a tile twenty times the size of the shape, and the shape shows one corner of one tile.

Patterns to copy

Each of these goes inside <defs>.

Diagonal stripes. Draw one upright stripe and turn the whole pattern with patternTransform:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="stripes" width="10" height="10" patternUnits="userSpaceOnUse"
      patternTransform="rotate(45)">
      <rect width="5" height="10" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#stripes)"/>
</svg>

Leave out patternTransform for vertical stripes, or use rotate(90) for horizontal ones.

Grid. Two edges of each tile are stroked, and the neighbouring tiles supply the other two:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
      <path d="M20 0H0V20" fill="none" stroke="teal" stroke-width="1"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#grid)"/>
</svg>

Checks. Two squares on opposite corners of the tile:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="checks" width="20" height="20" patternUnits="userSpaceOnUse">
      <rect width="10" height="10" fill="teal"/>
      <rect x="10" y="10" width="10" height="10" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#checks)"/>
</svg>

Crosshatch. Two lines across the tile, turned 45 degrees:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="hatch" width="8" height="8" patternUnits="userSpaceOnUse"
      patternTransform="rotate(45)">
      <path d="M0 4H8M4 0V8" stroke="teal" stroke-width="1"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#hatch)"/>
</svg>

A background colour behind the pattern

The gaps in a tile are transparent. For a solid colour behind the dots, put a rectangle the size of the tile first inside the pattern:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="spots" width="20" height="20" patternUnits="userSpaceOnUse">
      <rect width="20" height="20" fill="gold"/>
      <circle cx="10" cy="10" r="4" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#spots)"/>
</svg>

A fill can also name a colour after the pattern, fill="url(#spots) gold". That colour is a fallback, used only when the pattern cannot be found. It does not show through the gaps.

Where the tiles start

With userSpaceOnUse, the tiles are laid out from the origin of the drawing, the point 0,0, and not from the corner of the shape. A shape is a window on to the pattern: draw the same shape further along and it shows a different part.

  • To shift the pattern under the shape, set x and y on the <pattern>. A shape at x="7" with a pattern at x="7" starts on a whole tile.
  • A shape moved with a transform carries its pattern with it, because the transform moves the shape’s whole coordinate system. See SVG transform.

Anything in the tile that crosses its edge is cut off there. A dot centred on the corner of a tile shows as a quarter dot, not a whole one. Draw the other three quarters at the other three corners to make it whole.

Scaling the tile with a viewBox

A viewBox on the pattern lets the artwork use its own coordinates, scaled to the tile:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="stars" width="25" height="25" patternUnits="userSpaceOnUse" viewBox="0 0 10 10">
      <polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" fill="teal"/>
    </pattern>
  </defs>
  <rect width="200" height="100" fill="url(#stars)"/>
</svg>

The star is drawn in a box of 10 units and shown in tiles of 25. Change width and height and the star scales with the tile. When a pattern has a viewBox, patternContentUnits is ignored. SVG viewBox explained covers the four numbers.

Patterns on strokes and text

A pattern is a paint, so it works wherever a colour does:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
  <defs>
    <pattern id="pin" width="4" height="4" patternUnits="userSpaceOnUse">
      <rect width="3" height="4" fill="teal"/>
    </pattern>
  </defs>
  <circle cx="50" cy="50" r="35" fill="none" stroke="url(#pin)" stroke-width="14"/>
  <text x="100" y="65" font-size="44" font-weight="bold" fill="url(#pin)">Hi</text>
</svg>

The ring and the letters are both painted with the same stripes. Fill and stroke covers the other paints.

One tile, no repeat

A pattern always repeats. To show a picture once inside a shape, make the tile as large as the shape, which is what the default units are for: width="1" height="1" is one tile covering the whole bounding box. Often a clipping path is simpler: see SVG mask and clip-path.

A pattern as a page background

For the background of a web page there is no need for <pattern>. Save one tile as a small SVG file and let CSS repeat it:

body {
  background: url(tile.svg) repeat;
  background-size: 20px 20px;
}

SVG as a background image has the details, and SVG to data URI writes the tile into the stylesheet itself.

Common problems

What you seeCauseFix
The shape is emptyThe pattern has no width or height, or the id in url(#...) does not matchGive both sizes, and check the id letter for letter
Only one corner of one tile showswidth="20" without patternUnits="userSpaceOnUse"Add patternUnits="userSpaceOnUse"
The tiles stretch when the shape changes sizeThe default objectBoundingBox unitsUse userSpaceOnUse for a tile of fixed size
The artwork is cut off at the tile edgeThe tile clips its contentsMake the tile larger, or repeat the cut part on the opposite edge
The pattern does not line up with the shapeTiles start at 0,0 of the drawingSet x and y on the pattern
A second copy of the SVG shows the wrong patternTwo patterns in one page share an idGive each a different id
The fallback colour does not fill the gapsIt is used only if the pattern is missingPut a rectangle inside the tile
A line or a flat shape will not take the patternWith the default units, a bounding box with no width or no height cannot be divided into tilesUse userSpaceOnUse

Questions

Can a pattern contain a picture? Yes. A tile can hold an <image>, text, gradients, groups, or another shape filled with a different pattern.

Can a pattern be animated? Yes. patternTransform, x, y, width and height can all be animated with SVG animation elements, which makes the pattern slide or turn inside the shape.

Does a pattern make the file bigger? Hardly. The file holds one tile however many times it is shown, which is why a patterned fill is far smaller than the same dots drawn one by one.

Why is my pattern missing after optimising the file? An optimiser removes patterns that nothing in the file uses. If a pattern is used only by CSS or a script outside the file, keep its id: the SVG optimizer has a tick box for that.