1

I have an SVG that is essentially a box with rounded edges and borders on the corners of each edge:

<div class="container">
</div>
<svg width="258" height="258" viewBox="0 0 258 258" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M257 211.489L257 245C257 251.627 251.627 257 245 257L211.489 257" stroke="white" stroke-width="2" />
  <path d="M211.489 0.999998L245 0.999999C251.627 1 257 6.37258 257 13L257 46.5111" stroke="white" stroke-width="2" />
  <path d="M46.5111 257L13 257C6.37258 257 1 251.627 1 245L1.00001 211.489" stroke="white" stroke-width="2" />
  <path d="M1 46.5111V13C1 6.37258 6.37258 1 13 1H46.5111" stroke="white" stroke-width="2" />
</svg>

It's placed over a container div with a colored background:

body{background: white}
.container {
  margin-top: 70px;
  height: 400px;
  margin: 0 auto;
  background-color: black;
  opacity: 0.55;
}

svg {
  position: absolute;
  top: 50px;
  left: 300px;
}

I want the center of the SVG (the entire center area within the white edged borders) to be transparent. So in this example you would see the white background of the body.

Here's a CodePen of it: https://codepen.io/lance-p/pen/mdrwyyN

I was told that I could use a mask to achieve this but havent been able to get it to work. Any suggestions (with or without a mask) would be appreciated!

lance-p
  • 1,050
  • 1
  • 14
  • 28

1 Answers1

3

This is an alternative solution where I'm using a very wide shadow instead of the .container background.

Also I've simplified the svg but you can keep your code here.

*{margin:0;padding:0}

body {
  background: white;
}
.container {
  margin-top: 70px;
  height: 400px;
  margin: 0 auto;
  overflow: hidden;
  opacity: 0.55;
}

#hole {/*I want the hole to be slightly smaller than the svg element hence the calc*/
  width:calc(258px - 8px);
  height:calc(258px - 8px);
  border-radius:20px;
  position: relative;
  top: calc(50px + 4px);
  left: calc(300px + 4px);
  background:transparent;
  box-shadow:0 0 0 200vmax #000;
}

svg{
  width:258px;
  height:258px;
  position: absolute;
  top: 50px;
  left: 300px;
}
<div class="container">
  <div id="hole"></div>
</div>

  <svg width="258" height="258" viewBox="0 0 258 258" xmlns="http://www.w3.org/2000/svg">

    <rect x="1" y="1" width="256" height="256" rx="20" id="r" stroke="white" stroke-width="2" stroke-dasharray="80 168" stroke-dashoffset="58" fill="none" />

  </svg>

@alexandr_TT is commenting:

Can somehow highlight in the description the main solution for positioning the white corners stroke-dasharray="80 168" stroke-dashoffset="58"

First you need to know the total length of the rect with rounded corners. let l = r.getTotalLength();. You divide this value by 4 to know the total of a stroke and a gap: let stroke_gap = l/4; Next you choose one value for the stroke, for example let stroke = 80. For the gap you'll use let gap = stroke_gap - stroke; I've rounded the numbers. Maybe I shouldn't. This is giving me something like stroke-dasharray="80 168" If you are using only this the first stroke will begin at a distance of 20 units (rx = "20") from the corner (x="1" y="1") You will need a stroke-dashoffset to offset the strokes and make them bent around the corners.

You can calculate the lenght of the corner part of the path: It's the length of 1/4 of the perimeter of a circle with radius = 20 (rx=20): let corner = 2 * Math.PI * radius/4; The value for the stroke-dashoffset should be let sdo = stroke/2 + corner/2

let l = r.getTotalLength();
let radius = 20;
let stroke_gap = l/4;
let stroke = 80;
let gap = stroke_gap - stroke;

let corner = 2 * Math.PI * radius/4;
let sdo = stroke/2 + corner/2;

r.setAttribute("stroke-dasharray",`${stroke} ${gap}`)

r.setAttribute("stroke-dashoffset",sdo)
<svg viewBox="0 0 258 258" xmlns="http://www.w3.org/2000/svg">
  <rect x="1" y="1" width="256" height="256" rx="20" stroke="gold" stroke-width="5" fill="none" />

  <rect x="1" y="1" width="256" height="256" rx="20" id="r" stroke="black" stroke-width="2"  fill="none" />

  <path d="M1,21A20 20 0 0 1 21,1" stroke="red" fill="none" id="corner" />

</svg>
enxaneta
  • 31,608
  • 5
  • 29
  • 42
  • 1
    @enxaneta Great, helpful answer! Can somehow highlight in the description the main solution for positioning the white corners `stroke-dasharray="80 168" stroke-dashoffset="58"` – Alexandr_TT Dec 18 '20 at 11:00
  • 1
    @alexandr_TT I've updated my answer explaining this. Please bear in mind that in the previous demo I've rounded the numbers. Maybe I shouldn't have done it. – enxaneta Dec 18 '20 at 15:22
  • 1
    @enxaneta Excellent solution description! Sorry that my question took you some time, but it was useful and informative for everyone – Alexandr_TT Dec 18 '20 at 16:24
  • @enxaneta Can you please check this question https://stackoverflow.com/q/66025363/9004424 – Husna Feb 06 '21 at 07:56