Using SVG patterns for backgrounds in the Web

Using SVG patterns for backgrounds in the Web

Some time ago I needed to make a repeating pattern for a background of one web page, and not just a simple repeating background (made in CSS with background-repeat), but a pattern overlayed with a gradient, so it slowly changed color from one side of the page to the other. I wondered if it's possible to construct an SVG image with such pattern without manually copying each tile.

Turns out SVG is so packed with features, that it can easily do this. Here I'll describe the trick I have used.

With the <pattern> tag you can define any SVG image as a pattern, and then use it as a filling for other elements. Simple example:

<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="Pattern" x="0" y="0" width="48" height="48" patternUnits="userSpaceOnUse">
            <circle cx="24" cy="24" r="2" fill="black"/>
        </pattern>
    </defs>

    <rect width="100%" height="100%" fill="url(#Pattern)"/>
</svg>

Here the pattern is a 48x48 pixel image with a single black circle in the center. With the patternUnits attribute we basically define that we want this pattern to render in whatever SVG space it's being used, as if it was an element of that space.

After the <defs> tag we define a rectangle filling the entire SVG image with that pattern.

Using that tag we can make a simple yet interesting shape to work with. For example:

<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="Pattern" x="0" y="0" width="48" height="48" patternUnits="userSpaceOnUse">
            <rect x="0" y="0" width="48" height="48" fill="#3b73cf"/>
            <circle cx="48" cy="48" r="48" fill="#5f8cd7"/>
        </pattern>
    </defs>

    <rect width="100%" height="100%" fill="url(#Pattern)"/>
</svg>

Now, to overlay a gradient over that pattern, we'll have to use another two features of SVG: gradients (of course) and masks.

Let's start with a radial gradient. For example, this nice unintrusive one (#Gradient1):

<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="Pattern" x="0" y="0" width="48" height="48" patternUnits="userSpaceOnUse">
            <rect x="0" y="0" width="48" height="48" fill="#3b73cf"/>
            <circle cx="48" cy="48" r="48" fill="#5f8cd7"/>
        </pattern>

        <radialGradient id="Gradient1" cx="0%" cy="0%" r="100%">
            <stop offset="0%" stop-color="#3065ba" stop-opacity="1.0"/>
            <stop offset="100%" stop-color="#70a4e0" stop-opacity="1.0"/>
        </radialGradient>
    </defs>

    <rect width="100%" height="100%" fill="url(#Gradient1)"/>
</svg>

Its darker center is in the top left corner and it gets a bit lighter down and to the left.

Now, let's make the circular part of our pattern follow this gradient. To do that, we have make a mask – the same kind of masks that is used in Photoshop and other graphics apps. If you're not familiar with the concept, a mask is typically a black-and-white image. When we apply the mask to another image, whiteness of each pixel on the mask defines how much opacity will be applied to the pixel in the same position on the target image. So white pixels make the image 100% opaque, black pixels make it completely transparent, and different shades gray make it partially see-through.

If my explanation is not helpful, don't worry, there's an example below.

So, to achieve the desired effect, we have to use our pattern as a mask for the gradient. If we make the circular part of the pattern white and everything else black, we can make sure that the gradient is only visible on the circle.

Here's the mask (I just changed the colors of the pattern):

And here's how it looks applied:

<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="Pattern" x="0" y="0" width="48" height="48" patternUnits="userSpaceOnUse">
            <rect x="0" y="0" width="48" height="48" fill="black"/>
            <circle cx="48" cy="48" r="48" fill="white"/>
        </pattern>
        <mask id="Mask"><rect fill="url(#Pattern)" width="100%" height="100%"/></mask>

        <radialGradient id="Gradient1" cx="0%" cy="0%" r="100%">
            <stop offset="0%" stop-color="#3065ba" stop-opacity="1.0"/>
            <stop offset="100%" stop-color="#70a4e0" stop-opacity="1.0"/>
        </radialGradient>
    </defs>

    <rect width="100%" height="100%" mask="url(#Mask)" fill="url(#Gradient1)"/>
</svg>

The mask is defined with a <mask> tag, which wraps an SVG image to be used as a mask. We then use the mask attribute on the rectangle filled with the gradient.

To finish the background, let's make a slightly lighter gradient to fill the white parts. This time it's simpler, because it doesn't require a mask. We can just put our gradient behind the masked rectangle.

<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="Pattern" x="0" y="0" width="48" height="48" patternUnits="userSpaceOnUse">
            <rect x="0" y="0" width="48" height="48" fill="black"/>
            <circle cx="48" cy="48" r="48" fill="white"/>
        </pattern>
        <mask id="Mask"><rect fill="url(#Pattern)" width="100%" height="100%"/></mask>

        <radialGradient id="Gradient1" cx="0%" cy="0%" r="100%">
            <stop offset="0%" stop-color="#3065ba" stop-opacity="1.0"/>
            <stop offset="100%" stop-color="#70a4e0" stop-opacity="1.0"/>
        </radialGradient>
        <radialGradient id="Gradient2" cx="0%" cy="0%" r="100%">
            <stop offset="0%" stop-color="#3c7cc1" stop-opacity="1.0"/>
            <stop offset="100%" stop-color="#85b8e5" stop-opacity="1.0"/>
        </radialGradient>
    </defs>

    <rect width="100%" height="100%" fill="url(#Gradient2)"/>
    <rect width="100%" height="100%" mask="url(#Mask)" fill="url(#Gradient1)"/>
</svg>

The best part about this SVG is that since it has no width and height defined, it can scale to whatever size you want it to! You don't need to edit it, just use it as a background for an element of any size. You can make it cover the entire browser viewport and the pattern will always look good on any device.

That's it! I hope, I could show you something new about SVG.

Here are some other examples of what images can be produced with this tool set. Try reproducing these!


Photo by Andrew Ridley on Unsplash