Recursive SVG Designs, Part 1

Recently I’ve had a fascination with recursive SVG patterns: using multiple repetitions of a basic polygon inside itself to create complex designs. This requires precision alignment of scaled elements, which brings on another challenge: how to scale SVG elements around their centers.

The Fundamentals

Let’s start with the basic pattern unit of a hexagon, with all six points internally joined via a line to their opposite:

As this structure will be used repeatedly in the final design, it is created as a group inside the `<defs>` section of the SVG, with a `<use>` reference written to place the first iteration of the design:

``````<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 750 750">
<defs>
<g id="hex">
<polygon points="229.3,627.5 83.6,375.5 229.3,123.5 520.7,123.5 666.4,375.5 520.7,627.5" />
<line x1="229.3" y1="123.5" x2="520.7" y2="627.5"/>
<line x1="666" y1="375.5" x2="84" y2="375.5"/>
<line x1="520.7" y1="123.5" x2="229.3" y2="627.5"/>
</g>
</defs>
</svg>``````

The SVG is styled with written inside the `<defs>`:

``polygon, line { fill: none; stroke: #32679D; stroke-width: 7px; }``

Next, we want to create a copy of the pattern, but at half its current size, centered on the same point. But the line of code that you might use - a scaled `<use>` element:

``<use xlink:href="#hex" transform="scale(.5)" />``

…doesn’t work in the way you might expect:

Unlike HTML elements in CSS transformations, SVG does not scale around its center by default; instead, it scales from the top left corner. To get around this problem, we can use a simple formula:

translate(-centerX * (factor - 1), -centerY * (factor - 1)) scale(factor)

We know that the this design is centered at the precise center of the SVG i.e.: `375 375`. Therefore, to scale a copy of the design by half on this center point, the complete formula would be:

translate(-375 * (.5 - 1), -375 * (factor - .5)) scale(.5)

Which resolves to:

``<use xlink:href="#hex" transform="translate(187.5, 187.5) scale(.5)" />``

Creating this result:

The remaining problem - at least for this design - is that the `stroke` is scaled along with the design itself. Thankfully, from an earlier article, we know how to address that too: using `non-scaling-stroke` in CSS, or as an SVG attribute:

``````polygon, line {
fill: none; stroke: #32679D; stroke-width: 7px;
vector-effect: non-scaling-stroke;
}``````

The result:

Once you have that, it’s fairly straightforward to move and scale further copies of the base pattern to create complex designs.

Variants

One of the advantages of using a base pattern in SVG is that any changes to the base unit will be reflected in its copies. That is, if I rotate the original pattern in the `<defs>`:

``<g id="hex" transform="rotate(30 375 375)">``

All of the hexagons that derive from this base design will be rotated as a result, while retaining their individual translation and scale changes. You can see the effect of this in the example at the top of this article, and its associated CodePen.