Search code examples
svgsvg-transformssvg-pattern

How to create a repeating SVG pattern?


I have been given a design that uses this pattern in the background of a website

repeating hexagon pattern

I think an SVG pattern would be ideal for something like this. I can make an individual column of these shapes, but I am not sure if that could be better generated in a different way. What I am doing feels wrong and inefficient, and it would not scale to stretch across a screen for a background image.

svg {
  border: 1px solid #CCC;
}

svg * { 
  transform-box: fill-box;
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="780" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <path id="hex" fill="#D4C1DE" fill-opacity="0.3" d="M0 25.980762113533157L15 0L45 0L60 25.980762113533157L45 51.96152422706631L15 51.96152422706631Z">
  </defs>
  
    <use xlink:href="#hex" transform-origin="center" x="0" y="0"   transform="scale(0.20)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="400" transform="scale(0.30)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="450" transform="scale(0.40)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="500" transform="scale(0.50)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="550" transform="scale(0.60)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="600" transform="scale(0.70)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="650" transform="scale(0.80)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="700" transform="scale(0.90)" />
    <use xlink:href="#hex" transform-origin="center" x="0" y="730" />
</svg>

What is a more practical way to achieve the desired effect here?


Solution

  • Small change to Chris his great answer

    • Modern Browsers accept raw SVG as dataURI, no need for Base64

      • only have to replace linebreaks and " and #
    • a <svg-background> Web Component allows for SVG editting and see the result immediatly

    customElements.define( "svg-background", class extends HTMLElement {
        connectedCallback() {
          setTimeout(() => { // wait till <template> is parsed as DOM
            let svg = this.querySelector("template").innerHTML
                          .replace("#D4C1DE",this.getAttribute("fill") || "#D4C1DE")
                          .replaceAll("\n", "")    // replace linebreaks
                          .replaceAll('"', "'")    // replace double quotes
                          .replaceAll("#", "%23"); // escape #
            Object.assign(this.style, { // or document.body.style
              display: "block",
              width: "100vw",
              height: "100vh",
              backgroundImage: `url("data:image/svg+xml;utf8,${svg}")`,
              backgroundSize: "contain",
            });
          });
        }
      }
    );
    <svg-background fill="green">
      <template>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 500" fill="white">
          <defs>
            <path id="h" fill="#D4C1DE" fill-opacity="0.3" d="M-10-17.32 10-17.32 20 0 10 17.32-10 17.32-20 0Z" />
          </defs>
          <g id="g" transform="translate(0 20)">
            <use href="#h" transform="translate(0   0) scale(.2)" />
            <use href="#h" transform="translate(0  50) scale(.3)" />
            <use href="#h" transform="translate(0 100) scale(.4)" />
            <use href="#h" transform="translate(0 150) scale(.5)" />
            <use href="#h" transform="translate(0 200) scale(.6)" />
            <use href="#h" transform="translate(0 250) scale(.7)" />
            <use href="#h" transform="translate(0 305) scale(.8)" />
            <use href="#h" transform="translate(0 360) scale(.9)" />
            <use href="#h" transform="translate(0 420) scale(1)" />
          </g>
          <use href="#g" transform="translate(25 30)"/>
          <use href="#g" transform="translate(50 0)"/>
        </svg>
      </template>
    </svg-background>