Nathan Cox
Nathan Cox

Reputation: 33

SVG: Using a group as a mask

I'm trying to make an SVG image where I use one group of shapes as a mask for another.

Basically I want a group of transparent shapes that overlay a bigger shape and clip it, so you can see the page background through them (because they're transparent) but not the bigger shape's fill or stroke.

I tried applying a mask to the big shape that has a tag pointing to the #overlays group but it doesn't seem to work. Pointing the to an individual overlay DOES work but I don't want to put in a for every overlay.

Codepen: http://codepen.io/nathancox/pen/YPgZPR?editors=110

The top shape is the SVG, the bottom one is an image of what I'm trying to get it to do.

Here's the SVG:

<svg>
  <defs>
    <mask id="clip-behind" >
        <rect id="bg" x="0" y="0" width="100%" height="100%" fill="white"/>
        <use  xlink:href="#overlays" fill='black' fill-opacity='1' />
    </mask>
  </defs>

  <rect
     mask="url(#clip-behind)"
     width="260" height="270"  x="50" y="50"
     fill='none' stroke-opacity='1' stroke='black' stroke-width='4'
   />

  <g id="overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red'>
    <rect id='overlay1' width="80"  height="80" x="280" y="150" />
    <rect id='overlay2' width="50" height="50" x="140" y="300" />
  </g>
</svg>

Anybody know what I'm doing wrong, or if there's a better approach?

Upvotes: 2

Views: 1607

Answers (1)

Kaiido
Kaiido

Reputation: 136678

You won't be able to do it this way, <mask> uses alpha-channel to determine the opacity of masking ( black is clipped and white left ).

So in order to avoid semi-transparence of red mask, and because you can't change the already set fill property of elements contained in a <g> copied with <use>, you will have to link for an in <defs> <g>, without attribute, in the <mask> and in the document, and set their respective attributes then :


Really transparent :

body {
  background-color: #fff;
  background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
  background-size: 100% 1.2em;
}
svg {
  width: 400px;
  height: 400px;
}
<div id='container'>
  <svg>
    <defs>
      <g id="overlays">
        <rect id='overlay1' width="80" height="80" x="280" y="150" />
        <rect id='overlay2' width="50" height="50" x="140" y="300" />
      </g>
      <mask id="clip-behind">
        <rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
        <use xlink:href="#overlays"/>
      </mask>
    </defs>
    <rect mask="url(#clip-behind)" width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />
    <use xlink:href="#overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red' />
  </svg>

  <img src='https://dl.dropboxusercontent.com/u/587097/desired.png' />

</div>


Semi-transparent :

body {
  background-color: #fff;
  background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
  background-size: 100% 1.2em;
}
svg {
  width: 400px;
  height: 400px;
}
<div id='container'>
  <svg>
    <defs>
      <mask id="clip-behind">
         <rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
        <!-- changed the fill-opacity to make it more obvious -->
        <g id="overlays" fill='red' fill-opacity='0.8' stroke-opacity='1' stroke='red'>
        <rect id='overlay1' width="80" height="80" x="280" y="150" />
        <rect id='overlay2' width="50" height="50" x="140" y="300" />
    </g>
      </mask>
    </defs>
   
    <rect mask="url(#clip-behind)" width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />
    
  </svg>
</div>


<use xlink:href="#overlays" fill="black" fill-opacity="1"> displayed in normal view :
(still red semi-transparent)

body {
  background-color: #fff;
  background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
  background-size: 100% 1.2em;
}
svg {
  width: 400px;
  height: 400px;
}
<div id='container'>
  <svg>
    <defs>
      <g id="overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red'>
        <rect id='overlay1' width="80" height="80" x="280" y="150" />
        <rect id='overlay2' width="50" height="50" x="140" y="300" />
      </g>
    </defs>
    <rect width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />

    <use xlink:href="#overlays" fill="black" fill-opacity="1" />

  </svg>
</div>

Upvotes: 3

Related Questions