How to center an svg <pattern> inside a larger responsive container at all possible widths?

366 views Asked by At

I have a responsive SVG container and I need my <pattern> to appear centered on every situation.

I mean:

  • The <pattern> triangle should be centered at all possible widths
  • And the space on left/right must repeat the triangle <pattern>

Is this possible? I know it's possible dynamically recalculating the pattern position with JS. But I would like to do it using svg properties only.

.mySvg1 {
  width: 600px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

.mySvg2 {
  width: 400px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

.mySvg3 {
  width: 200px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

span {
  font-weight: bold;
  color: red;
}

.myDiv1 {
  margin-bottom: 16px;
}
 <div class="myDiv1">
   SEE THAT THE TRIANGLE IS <span>NOT</span> CENTERED. I WOULD LIKE IT TO ALWAYS BE CENTERED
 </div>

<div>
  <svg class="mySvg1">
    <defs>
      <pattern 
        id="wave"
        width="150"
        height="50"
        patternUnits="userSpaceOnUse"
      >
        <path d="M 0 50 l 75 -50 l 75 50" stroke="black" stroke-width="2"/>
      </pattern>
    </defs>
    <rect x="0" y="0" width="100%" height="100%" fill="url(#wave)"/>
  </svg>
</div>

<div>
  <svg class="mySvg2">
    <rect x="0" y="0" width="100%" height="100%" fill="url(#wave)"/>
  </svg>
</div>

<div>
  <svg class="mySvg3">
    <rect x="0" y="0" width="100%" height="100%" fill="url(#wave)"/>
  </svg>
 </div>

EXTRA:

It's easy to do it with background-image. I would like to do the same using <svg> only. Is this possible?

div {
  margin-bottom: 16px;
}

.myDiv1 {
  width: 600px;
  height: 50px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 -2 150 52"><path d="M 0 50 l 75 -50 l 75 50" stroke="black" /></svg>');
  background-position: center;
}

.myDiv2 {
  width: 400px;
  height: 50px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 -2 150 52"><path d="M 0 50 l 75 -50 l 75 50" stroke="black" /></svg>');
  background-position: center;
}

.myDiv3 {
  width: 200px;
  height: 50px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 -2 150 52"><path d="M 0 50 l 75 -50 l 75 50" stroke="black" /></svg>');
  background-position: center;
}
<div>
  SEE THAT THE TRIANGLE IS ALWAYS CENTERED
</div>

<div class="myDiv1">
</div>

<div class="myDiv2">
</div>

<div class="myDiv3">
</div>

1

There are 1 answers

3
Temani Afif On

Here is an idea where you need to:

  1. set a big width to the rect considering the width of path (an odd multiplier of the width of the path)
  2. you make the width of the pattern using percentage (100/n where n is the multiplier). You also remove patternUnits="userSpaceOnUse"
  3. You place the rect at 50% and you translate it back with 50% to have it in the middle

In other words, we make the rect very big and we center it inside the SVG. The odd multiplier is to make sure the center of rect is the centre of a triangle and not the between two triangles.

.mySvg1 {
  width: 600px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

.mySvg2 {
  width: 400px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

.mySvg3 {
  width: 200px;
  height: 50px;
  border: 1px dotted red;
  margin-bottom: 16px;
}

span {
  font-weight: bold;
  color: red;
}

.myDiv1 {
  margin-bottom: 16px;
}

rect {
  transform:translate(-50%);
  transform-box:fill-box;
}
<div class="myDiv1">
   SEE THAT THE TRIANGLE IS <span>NOT</span> CENTERED. I WOULD LIKE IT TO ALWAYS BE CENTERED
 </div>

<div>
  <svg class="mySvg1">
    <defs>
      <pattern 
        id="wave"
        width="9.1%"
        height="50"
      >
        <path d="M 0 50 l 75 -50 l 75 50" stroke="black" stroke-width="2"/>
      </pattern>
    </defs>
    <rect x="50%" y="0" width="1672" height="100%" fill="url(#wave)" />
  </svg>
</div>

<div>
  <svg class="mySvg2">
    <rect x="50%" y="0" width="1672" height="100%" fill="url(#wave)"/>
  </svg>
</div>

<div>
  <svg class="mySvg3">
    <rect x="50%" y="0" width="1672" height="100%" fill="url(#wave)"/>
  </svg>
 </div>