Masque SVG ou style CSS pour éliminer le centre du svg afin qu'il soit transparent

Dec 18 2020

J'ai un SVG qui est essentiellement une boîte avec des bords arrondis et des bordures aux coins de chaque bord:

<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>

Il est placé sur un conteneur div avec un fond coloré:

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;
}

Je veux que le centre du SVG (toute la zone centrale dans les bordures blanches) soit transparent. Donc, dans cet exemple, vous verriez le fond blanc du corps.

En voici un codePen: https://codepen.io/lance-p/pen/mdrwyyN

On m'a dit que je pouvais utiliser un masque pour y parvenir, mais je n'ai pas réussi à le faire fonctionner. Toutes les suggestions (avec ou sans masque) seraient appréciées!

Réponses

3 enxaneta Dec 18 2020 at 17:23

C'est une solution alternative où j'utilise une ombre très large au lieu de l' .containerarrière - plan.

J'ai également simplifié le svg mais vous pouvez garder votre code ici.

*{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 commente:

Peut en quelque sorte mettre en évidence dans la description la solution principale pour positionner les coins blancs stroke-dasharray = "80 168" stroke-dashoffset = "58"

Vous devez d'abord connaître la longueur totale du rect aux coins arrondis. let l = r.getTotalLength();. Vous divisez cette valeur par 4 pour connaître le total d'un trait et d'un espace: let stroke_gap = l/4;Ensuite, vous choisissez une valeur pour le trait, par exemple let stroke = 80. Pour l'écart que vous utiliserez, let gap = stroke_gap - stroke;j'ai arrondi les chiffres. Peut-être que je ne devrais pas. Cela me donne quelque chose comme stroke-dasharray="80 168"si vous n'utilisez que cela, le premier coup commencera à une distance de 20 unités (rx = "20") du coin (x = "1" y = "1") Vous aurez besoin d'un stroke-dashoffsetpour décalez les traits et pliez-les autour des coins.

Vous pouvez calculer la longueur de la partie d'angle du tracé: C'est la longueur de 1/4 du périmètre d'un cercle avec un rayon = 20 (rx = 20): let corner = 2 * Math.PI * radius/4;La valeur du décalage de trait-tiret doit êtrelet 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>