svg

Why does SVG mask become partially transparent with "use"


The two code blocks below are the same, except for the "use" tag in the second to attempt to reuse the #p1 circle.

Why does switching to "use" result in the mask becoming partially transparent? And is there a method to maintain the opacity, yet reuse the #p1 circle?

<style>
  svg { background-color:#aaa }
  #p1 { fill:blue }
  #p2 { fill:red }
  #p3 { fill:green }
</style>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <mask id="m1">
      <rect width="100%" height="100%" fill="white" />
      <circle r="65" cx="150" cy="100" fill="black" />
    </mask>
  </defs>
  <circle id="p1" r="65" cx="150" cy="100" />
  <circle id="p2" r="65" cx="180" cy="175" />
  <circle id="p3" r="65" cx="100" cy="175" mask="url(#m1)" />
  <circle r="45" cx="150" cy="150" fill="white" />
</svg>

<style>
  svg { background-color:#aaa }
  #p1 { fill:blue }
  #p2 { fill:red }
  #p3 { fill:green }
</style>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <mask id="m1">
      <rect width="100%" height="100%" fill="white" />
      <use href="#p1" fill="black" />
    </mask>
  </defs>
  <circle id="p1" r="65" cx="150" cy="100" />
  <circle id="p2" r="65" cx="180" cy="175" />
  <circle id="p3" r="65" cx="100" cy="175" mask="url(#m1)" />
  <circle r="45" cx="150" cy="150" fill="white" />
</svg>


Solution

  • Like commented this has nothing to do with the <use> element itself.

    If I take your second example, and move the <use> element from the mask to the end of the SVG, you can see the fill color -- it is blue even though you have the fill attribute value set to black. Like Michael Mullany mentions in the comment, that makes the mask semi transparent.

    <style>
      svg { background-color:#aaa }
      #p1 { fill:blue }
      #p2 { fill:red }
      #p3 { fill:green }
    </style>
    <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <mask id="m1">
          <rect width="100%" height="100%" fill="white" />
        </mask>
      </defs>
      <circle id="p1" r="65" cx="150" cy="100" />
      <circle id="p2" r="65" cx="180" cy="175" />
      <circle id="p3" r="65" cx="100" cy="175" mask="url(#m1)" />
      <circle r="45" cx="150" cy="150" fill="white" />
      <use href="#p1" fill="black" />
    </svg>

    My guess is that you would like to make the circles cover each other, so that it looks like they are intertwined. You can do that by having a mask that "reveals" the current circle, but covers the previous one.

    <svg viewBox="0 0 220 200" width="300" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <mask id="mask">
          <use href="#p1" fill="white" />
          <use href="#p1" fill="black" transform="rotate(-120)" />
        </mask>
        <circle id="p1" r="65" cy="-40"/>
      </defs>
      <g transform="translate(110 110)">
        <use href="#p1" fill="blue" mask="url(#mask)" />
        <use href="#p1" fill="red" mask="url(#mask)" transform="rotate(120)" />
        <use href="#p1" fill="green" mask="url(#mask)" transform="rotate(240)" />
      </g>
    </svg>