Clip-paths*and Masks

Like the slightly more complex <mask> (that we'll introduce later), the <clipPath> tag gives us a way to define a collection of shapes that may be used to carve a given figure into more interesting shapes. A clip-path may be applied to any drawn objects in SVG including groups of objects, and the clip-path itself can consist of many shapes. Masks are a lot like clip-paths, but more flexible. We'll show just one simple example of masks here, and let the SVG Primer lead you further if you are interested.

Some of the experiments with gradients might suggest that we can use stop-opacity of a gradient to simulate certain kinds of cropping or clipping.

In particular let's use a radial gradient to restrict the appearance of a rectangular bitmap to an elliptical region.
Webster's 1911 fire engine engraving
Gradient to be used as mask
Gradient, with hole, atop fire engine
<image x="15%" width="30%" y="15%" height="30%"
xlink:href="fireenginefromWebsters1911.gif" />
<radialGradient id="r" fy=".55" >
<stop offset=".3" stop-opacity="0"/>
<stop offset=".8" stop-color="black" />
<stop offset=".9" stop-color="white" />
<stop offset="1" stop-color="brown"/>
</radialGradient>
<rect x="15%" y="15%" height="30%"
width="30%" fill="url(#r)"/>
<radialGradient id="r" fy=".55" >
<stop offset=".3" stop-opacity="0"/>
<stop offset=".8" stop-color="black" />
<stop offset=".9" stop-color="white" />
<stop offset="1" stop-color="brown"/>
</radialGradient>
<image x="15%" width="30%" y="15%" height="30%"
xlink:href="fireenginefromWebsters1911.gif" />
<rect x="15%" y="15%" height="30%" width="30%"
fill="url(#r)"/>
A simple bitmap imported into SVG through <image> A gradient with transparent center. Overlaying the two

This serves to illustrate some of the power of gradients, but it should be fairly straightforward to conclude that using linear and radial gradients (the only kind available in SVG at present) to "clip" an image down to an arbitrary shape will not be easy!

Here's the above effect but swapping in a different image:

A similar effect can be just as easily accomplished in the following way

<clipPath id="CP">
<ellipse cx="29%" cy="26%" rx="10%" ry="8%"/>
</clipPath>
<image y="0" x="10%" width="40%" height="55%"
xlink:href='p17.jpg' clip-path="url(#CP)"/>
Picture of clipped bitmap

Picture of clipped bitmap

Basically, we can see from the above example, that like gradients, tags are put inside a <clipPath> and then the clip-path can be applied (through its "id") to the object or group of objects to be clipped.

Let's try something like that with a group of objects:

<clipPath id="CP">
<ellipse cx="29%" cy="26%" rx="10%" ry="8%"/>
</clipPath>

<g clip-path="url(#CP)">
<image y="0" x="10%" width="40%" height="55%"
xlink:href='p17.jpg' />

<rect y="0" x="15%" width="10%" height="55%"
fill="purple" opacity=".6" />

<rect y="0" x="33%" width="10%" height="55%"
fill="yellow" opacity=".8" />

</g>
Group with rects and image clipped by ellipse

Next, we will see an example that clearly differentiates between what we might accomplish with clip-paths as opposed to gradients. In the following example we insert numerous ellipses into the clip-path showing that the clipped regions may be complex.

<clipPath id="CP">
<ellipse cx="19%" cy="25%" rx="2.5%" ry="4%"/>
<ellipse cx="24%" cy="25%" rx="2.5%" ry="4%"/>
<ellipse cx="29%" cy="25%" rx="2.5%" ry="4%"/>
<ellipse cx="34%" cy="25%" rx="2.5%" ry="4%"/>
<ellipse cx="39%" cy="25%" rx="2.5%" ry="4%"/>
</clipPath>
<g clip-path="url(#CP)">
<image y="0" x="10%" width="40%" height="55%"
xlink:href='p17.jpg' />

<rect y="0" x="15%" width="10%" height="55%"
fill="purple" opacity=".6" />

<rect y="0" x="33%" width="10%" height="55%"
fill="yellow" opacity=".8" />

</g>
Five ellipses clipping a bitmap

Following this example, one might be tempted to try something like the following:

<clipPath id="CP">
<g id="U">
<ellipse cx="19%" cy="25%" rx="2.5%" ry="4%" />
<ellipse cx="24%" cy="25%" rx="2.5%" ry="4%" />
<ellipse cx="29%" cy="25%" rx="2.5%" ry="4%" />
<ellipse cx="34%" cy="25%" rx="2.5%" ry="4%" />
<ellipse cx="39%" cy="25%" rx="2.5%" ry="4%" />
</g>
<use xlink:href="#U" transform="translate(0,40)" />
<use xlink:href="#U" transform="translate(0,80)" />
</clipPath>

However, by the SVG specification 1.1, the content of a clipPath cannot involve either groups (<g>) or complex uses (<use>). A clip-path is limited to either simple drawn objects, or to reuses of simple drawn objects. If we wanted to reuse content as above, we could do so through a <mask> as follows:

<mask id="CP">
<g id="U">
<ellipse cx="19%" cy="25%" rx="2.5%" ry="4%" fill="white"/>
<ellipse cx="24%" cy="25%" rx="2.5%" ry="4%" fill="white"/>
<ellipse cx="29%" cy="25%" rx="2.5%" ry="4%" fill="white"/>
<ellipse cx="34%" cy="25%" rx="2.5%" ry="4%" fill="white"/>
<ellipse cx="39%" cy="25%" rx="2.5%" ry="4%" fill="white"/>
</g>

<use xlink:href="#U" transform="translate(0,40)" />
<use xlink:href="#U" transform="translate(0,80)" />
</mask>

<g mask="url(#CP)">
<image y="0" x="10%" width="40%" height="55%"
xlink:href='p17.jpg' />

<rect y="0" x="15%" width="10%" height="55%" fill="purple"
opacity=".6" />

<rect y="0" x="33%" width="10%" height="55%" fill="yellow"
opacity=".8" />

</g>
reusing a group of ellipses inside a mask

In this example the white ellipses act exactly like the positive parts of the clip-path that include content of the affected image. Parts of the images corresponding to black or unfilled parts of the mask are completely excluded.

While a clip-path declares that content is either inside it (and hence visible) or outside it (and hence invisible) a mask allows degrees of visibility, depending on the brightness of the objects inside the mask. Herewith is a fairly complex example that places a reflected gradient inside a mask so that opacity values of the affected image undergo gradual transitions across the bands of the gradient:

<radialGradient id="G1" cx="29%" cy="27%" r="45" fy="50%"
spreadMethod="reflect" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="grey"/>
<stop offset="0.5" stop-color="white" />
<stop offset="1" stop-color="black"/>
</radialGradient>
<mask id="M">
<ellipse cx="29%" cy="35%" rx="10%" ry="20%" fill="url(#G1)"/>
</mask>

<rect y="140" x="23%" width="5%" height="55%" fill="cyan" />
<rect y="140" x="30%" width="5%" height="55%" fill="green" />
<g mask="url(#M)" transform="translate(0,90)">
<image y="0" x="10%" width="40%" height="60%" xlink:href='p17.jpg' />
<rect y="0" x="15%" width="10%" height="60%" fill="purple" opacity=".6" />
<rect y="0" x="33%" width="10%" height="60%" fill="yellow" opacity=".8" />
</g>
mask containing reflected gradient

*I am never quite sure whether to type "clippaths" or "clip-paths." In SVG there is a tag <clipPath> and an attribute clip-path. To my way of thinking , "clip-path" sounds a bit more consistent with English spelling (if anyone would be so brave as to suggest that this strange language has anything resembling spelling rules). I probably will not be consistent with myself, though.