The ultimate guide to creating SVG patterns for websites

By Matt Visiwig Matt Visiwig Portrait Mar 10, 2022

We’re gonna take an indepth look at how to create patterns, so you know how to approach designing patterns with SVG.

The four pattern-making skills you are going to learn are:

Three pattern styles we'll learn: alternating, hexagon, and organic
Three pattern styles we’ll learn: alternating, hexagon, and organic

How identify pattern tiles

When you can look at a repeating pattern and see the tile, you’ll quickly understand how it was built. More importantly, when something goes wrong while building your own patterns, the ability to identify tiles translates to the ability to identify why a pattern doesn’t look right. 

Understanding the pattern tile

The tile is the smallest unit of a pattern. A pattern is formed when the pattern tile is cloned into a grid, where all columns and rows share the width and height of the tile respectively. Most pattern tiles are rectangular, but patterns can be made from other repeating shapes, such as hexagons.

In SVG, the tile must be rectangular. Even patterns that were originally made from hexagonal tiles, can be recreated as in rectangular form.

Finding a tile in a seamless pattern

When determining the tile of a seamless pattern, we want to systematically locate repeating features in the pattern.

The steps to identify the pattern tile:

  1. Identify a repeating feature in the design
  2. Mark a unique point on that feature
  3. Move horizontally to find and mark the next instance at the same point
  4. Move vertically from both marks to find that same instance, mark those points

In this quatrefoil pattern, first I’d note there are many dark and light purple shapes and mark the tip a dark point. Then moving to the right, find the same point on the next dark shape. And do the same for the spots under those two points.

The steps of identifying a pattern tile
The steps of identifying a pattern tile

Finding tiles in complex patterns
In most cases, you will mark four points that form a rectangle on the first try, and locate the tile.

However, complex patterns with large tiles can have repeating elements within the tile, making this exercise more challenging. In that case you may need to expand the boundaries of your points or pick different features and try again. 

Worse, the tiles could be rotated, so instead of moving horizontally, and vertically, you may have to adjust accordingly and move at an angle.

How to position elements within tiles

Now that you can identify rectangular tiles in patterns, you’re ready to learn how to create your own tiles.

When you place any shape within the boundaries of a tile, it will nicely repeat as a pattern.

That changes when you place that same element where it crosses a boundary (AKA edge) of the tile. In this situation, the element will appear clipped in the pattern.

circles get clipped on left edge of tile
The circle get clipped on left edge of tile

The way to prevent this clipping is to clone the same element on the opposite boundary. If the boundary falls on a corner, clone the element on all the other tile corners. 

How do we make sure the clones align perfectly? It’s simple math. When we’re dealing with the left and right boundaries, you’ll add or subtract the tile’s width to the X coordinate and keep identical Y coordinates. Use the height for top and bottom calculations. Use a combo of the width and height for the corner boundaries. 

How to design and code SVG Patterns (3 different styles)

We’re going to demonstrate how to design and code three patterns, all with a different technique.

Designing an alternating pattern

Alternating patterns are relatively simple, making it perfect for an introduction to the pattern element.

First we’re going to declare an empty 100×100 pattern. 

<pattern width="100" height="100">

</pattern>

By default the pattern’s coordinate system (patternUnits='objectBoundingBox') is percentage-based which is awkward because patterns distort to fit the container. Instead, I build everything using patternUnits='userSpaceOnUse' because the coordinate system behaves consistently whether the container is fixed (pixel-based) or fluid (percentage-based). It’s no different than working with the default viewBox coordinate system.

<pattern patternUnits="userSpaceOnUse" width="100" height="100">

</pattern>

Let’s create a simple pattern by placing a circle in the center.

<pattern id='my_pattern' width='100' height='100' patternUnits='userSpaceOnUse'>
   <circle cx="50" cy="50" r="25" />
</pattern>

Notice I snuck in an id of #my_pattern, so now I can get the pattern to display on another element. I typically place it on a fullscreen rectangle as demonstrated below, but you can also use the pattern as a fill to any shape, such as a circle.

<rect fill='url(#my_pattern)' width='100%' height='100%'/>

At this point we can now see the pattern, but the trick to making an alternating pattern is to also place the shape on all four corners. Note that the fist shape doesn’t have an X or Y coordinate, which will default to the coordinate [0, 0].

<circle r="25" /><!-- top left -->
<circle cx="100" r="25" /><!-- top right -->
<circle cy="100" r="25" /><!-- bottom left -->
<circle cx="100" cy="100" r="25" /><!-- bottom right -->

Here is the entire SVG pattern where the center circle has a blue fill.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200">
   <pattern id="p" width="100" height="100" patternUnits="userSpaceOnUse">
      <circle fill="blue" cx="50" cy="50" r="25" />
      <circle r="25" /><!-- top left -->
      <circle cx="100" r="25" /><!-- top right -->
      <circle cy="100" r="25" /><!-- bottom left -->
      <circle cx="100" cy="100" r="25" /><!-- bottom right -->
   </pattern>
   <rect fill="url(#p)" width="100%" height="100%"/>
</svg>

The viewBox is 400×200 and our pattern tile is 100×100. The SVG will show 8 tiles (4×2), because the pattern fills a rectangle element that stretches the entire viewBox.

Designing a pattern with hexagonal tiles

Creating hexagonal tiles is a challenge in SVG, because tiles need to be defined as rectangular tiles.

To calculate the tile width and height, let’s use our first lesson on how to identify tiles.

Marking the tile of a hexagon pattern
Identifying the tile of a hexagon pattern

Looking at our hexagon pattern, I marked the left-most point of the hexagon and found matching spots horizontally and vertically. Using our eyes, we can tell the tile height will be equal to the height of one flat hexagon. The tile width is the width of the hexagon plus the distance of one side. 

There are a few ways to determine these numbers. Actually measure the distance in a vector software like Illustrator or Google a formula (I chose the latter). The diameter is double the size of one side, so the width is the side multiplied by 3. The height is about 1.732 times bigger than the side and through a little trial and error I settled on some numbers that would have minimal rounding for the tile: 180×104.

Pattern tiles can handle decimals, but I prefer to create tiles where elements fall on whole pixels, as decimals can lead to thin lines or detailed designs blurring.

A single tile for a hexagon pattern
<pattern id="pttn" width="180" height="104" patternUnits="userSpaceOnUse">
   <g fill="none" stroke="#808" stroke-width="20">
      <path d="M90 0H30L0 52l30 52h60l30-52z"/>
      <path d="M120 52h60"/>
   </g>
</pattern>
<rect fill="url(#pttn)" width="100%" height="100%"></rect>

When you view the results closely, you may notice a little clipping in the tile. What’s wrong? The stroke of the hexagon crosses the left boundary and we need to compensate for that. The stroke also crosses the top and bottom boundaries, but in a way that matches and doesn’t need adjustment.

We have a few options to fix the right boundary and I’ll show you two strategies to tackle this challenge. 

Solution 1
Recreate the hexagon or the portion of it that is clipping. You can draw up another hexagon path, but one way to clone shapes easily is the <use> element.

First, give the source element an id="" and reference it with an href="" attribute in our <use> element. Lastly, it will be placed at the same coordinates, so we need to add the tile width (180) to the X coordinate. The clipping no longer occurs. You can use this trick in most patterns that suffer from boundary clipping.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 240">
   <pattern id="p" width="180" height="104" patternUnits="userSpaceOnUse">
      <g fill="none" stroke="#808" stroke-width="15">
         <path id="a" d="M90 0H30L0 52l30 52h60l30-52z"/>
         <path d="M120 52h60"/>
         <use href="#a" x="180"/>
      </g>
   </pattern>
   <rect fill="url(#p)" width="100%" height="100%"></rect>
</svg>

Note: if your not using HTML 5, you must include the xmlns:xlink="http://www.w3.org/1999/xlink" declarative attribute in the SVG element for the <use> element to work.

Solution 2
The first solution is useful in many situations, but sometimes, it’s more elegant to position your elements in a way that avoids boundary clipping altogether. 

We can simply place the hexagon in the horizontal center to avoid the same clipping issues we experienced in our first pattern.

Hexagon tile centered

Here is the pattern code to this solution:

<pattern id="pttn" width="180" height="104" patternUnits="userSpaceOnUse">
   <g fill="none" stroke="#808" stroke-width="15">
      <path d="M120 0H60L30 52l30 52h60l30-52z"/>
      <path d="M150 52h30"/>
      <path d="M0 52h30"/>
   </g>
</pattern>

You can optimize the paths by merging them into a single element, removing the need for the g element:

<pattern id="pttn" width="180" height="104" patternUnits="userSpaceOnUse">
      <path stroke="#808" stroke-width="15" d="M120 0H60L30 52l30 52h60l30-52zM150 52h30M0 52h30" fill="none"/>
</pattern>

Designing a large organic doodle pattern

Instead of creating a new pattern, let’s dissect and reverse engineer a pattern that I grabbed from an SVGBackgrounds.com pattern collection. This time we’ll choose an organic doodle pattern where the shapes feel randomly placed.

We already know how to identify the tile, let’s start there.

Identifying the pattern tile

If we kept all the shapes away from the boundary, the tile seams would be obvious. In this style of design, it’s important that all attributes get distributed evenly or your eye will get drawn to unique spots of the element.

I moved a single doodle element out of place and your eye gets drawn to the ripple in the resulting pattern.

Slightly off element causes noticeable ripple
Slightly off element causes noticeable ripple

This applies to all aesthetic features from colors, size, spacing, shape, quantity, and placement, as demonstrated above. When a pattern has one big shape, your eye gets drawn to that. When one color stands out in particular, your eyes notice those repetitions much easier. 

To hide the seams of a pattern, aim to have an even frequency and distribution of design elements.

Next let’s check out the edges. I color-coated shapes that extend past the boundaries. Note that you can reach for the <use> element to clone the entire pink section and do the same for the sky blue section.

Color coating the pattern edge clones

Making a design like this requires vector software like Illustrator or Inkscape. You’d likely place the edge pieces first, like a puzzle and then find natural placements for the other shapes to fill the canvas. 

In any case, you will probably need to adjust pieces multiple times to get it just right. If you need to move an edge piece, make sure to translate the opposite edge piece in the same manner.

You could create a pattern right in Illustrator for export, but hand coding the <pattern> element is necessary to achieve a highly optimized SVG. 

If you dissect the pattern’s code, you’ll notice the <use> elements clone the edge pieces as noted above. You can also tell decimals were removed from the paths because organic shapes don’t rely on precision. I wrote in depth about SVG optimization, if you’d like to learn other tricks to reduce filesize.

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600'>
    <rect fill='#46315d' width='800' height='600' />
        <pattern id='c' width='800' height='600' patternUnits='userSpaceOnUse'
            patternTransform='scale(.4)'>
            <g fill='none' stroke='#735098' stroke-width='30' stroke-linecap='round'>
                <path
                    d='M109 57c0 41 20 60 60 60M439 128c40-6 56-28 51-68M523 138c35 21 61 14 82-20M405 294c-23 34-17 61 16 84M445 328c38-15 50-40 36-78M511 347c37-17 47-43 30-80M626 391c26-31 23-59-8-84M581 359c-32 25-35 52-10 84M752 415c3-40-15-61-56-64M252 139c-40 0-60 20-60 60M762 545c-4-40-25-58-66-54M584 562c40 0 60-19 60-60M624 179c-37 18-46 44-28 80M167 247c-30 27-32 54-5 85M425 241c-38-12-63 1-74 40M343 366c-9-40-32-55-72-46M622 445c39 12 64-1 76-40M512 458c15 37 40 49 78 34M111 349c-39 11-53 34-43 74M189 385c4 41 26 58 66 54M     314 442 c0-41-20-60-60-60M90 478c38-13 50-38 36-76M682 281c28 29 56 29 84 0M760 113c-27 29-26 57 4 84M245 255c-36 18-44 45-26 80M275 33c-40-1-60 17-62 58M325 149c0-40-19-60-60-60M714 89c-39 11-53 35-42 74M727 243c-25-32-53-35-84-10M345 197c38-13 50-38 36-76M524 214c-20-36-46-43-82-24M81 225c41 0 60-19 60-60M300 264c5-41-12-62-52-67M162 548c-28-29-55-30-84-2M496 398c-38 13-51 37-38 76M356 543c-8-40-30-55-70-48M242 529c-11-39-35-53-74-42M378 413c-17 37-7 63 30 80M410 552c38 15 63 3 78-34' />
                <path id='a'
                    d='M5 325c40 8 63-8 70-48M39 478c-33 24-37 51-13 84M-23 459c36-18 45-44 26-80M46 184c-36 18-45 44-28 80M-29 53c25 31 53 34 84 9M90 157c-23-34-50-39-84-16M-17-9c27 30 54 32 84 5M-17 591c27 30 54 32 84 5' />
                <path id='b'
                    d='M332-12c-13 39 0 63 38 76M578 13c-35 21-41 48-20 82M473 9c41 0 60-20 60-60M423 78c15-38 4-63-34-78M698 39c31-26 33-54 6-84M664-11c-36 19-44 46-25 82M163 65c11-39-3-63-42-74M208-26c36 19 62 12 82-24' />
                <use xlink:href='#a' x='800' />
                <use xlink:href='#b' y='600' />
            </g>
        </pattern>    
    <rect fill='url(#c)' width='100%' height='100%' />
</svg>

How to apply SVG patterns to a webpage

Now that we can create our own patterns, we want to place the patterns as backgrounds on websites.

There are three approaches to adding SVG patterns to a website:

  1. SVG tiling: SVG file as the entire background
    We’ve created SVG code with the <pattern> element which already handles the tiling and gives us advanced control, such as rotation, scaling, translation, and skew.
  2. CSS tiling: SVG file as the tile
    This method leans on CSS to handle the tiling. In this case the SVG should not have a <pattern> element wrapping the tile, but doesn’t change the rules for designing tiles.
  3. Inline SVG for advanced control
    If you prefer to inline your SVG to be able to manipulate the SVG design with CSS or JS, you can instead follow this tutorial on how to inline your background, as the next steps don’t apply.

Whether you choose SVG or CSS tiling, you will add your SVG pattern as a background-image via CSS.

First we’ll create a class and place the path to the SVG file as the value of the background-image property like so:

.your-class{
   background-image: url("/path/to/file.svg");
}

This is no different from adding a JPG as the background image. 

Then there are a few other properties to consider to get the pattern to display the way you intend.

  1. Background-size: cover;
    This declaration is good when stretching SVG across the entire screen, which is relevant if you’re using SVG tiling.
  2. Background-size: auto;
    This is a default value, which is necessary for CSS tiling, so you need this declaration if value auto is overridden for any reason.
  3. Background-position: center;
    This is optional, but useful if you’d like to center your pattern, as your pattern is anchored to the top left corner of the background container by default.
  4. Background-repeat: no-repeat;
    If we’re relying on the SVG for tiling, we don’t want any CSS tiling. But you don’t need this declaration if you use background-size: cover, which displays a single tile.
  5. Background-repeat: repeat;
    This is a default value, which is necessary for CSS tiling. Alternatively, you can also use the values repeat-x or repeat-y, if you only want a single column or row of tiles.
  6. Background-attachment: scroll | fixed;
    This property determines how the background displays with your content. A value of scroll is the default and keeps the background scrolling with its container. A value of fixed gives a parallax effect, where the background is attached to the screen and stays in place while you scroll.

What we’ve learned about SVG Patterns

We’ve gone over how to identify patterns and position elements within these tiles to ensure they display seamlessly. 

We demonstrated the process of designing three unique SVG pattern styles, showcasing various techniques and strategies to help you create your own patterns.

Lastly, we talked about ways to apply these background patterns on websites using CSS.

Now you’re ready to go out and make your own patterns.

If you’d like pattern inspiration or to have loads of SVG patterns at your disposal, I’ve designed hundreds of free and paid SVG patterns. You can access them at:

Matt Visiwig Headshot

Hey, I'm , the creator behind SVG Backgrounds. I produce a free resource every few months, sign up for alerts.