Reputation: 33
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
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