SVG Masks and Clip Paths

One of the fun things to explore is how we can mask and clip SVG elements and how we can do “text on a path” effects. As we explore these new elements we’ll visit additional elements that make part of the mask and path functionality and how CSS interacts with SVG (TL, DR: It doesn’t use the same elements).

Masks

mask Defines an alpha mask for compositing the current object into the background. It will ‘bleed’ the background into the foreground element

The pattern element defines a graphics object which you can tile (repeat at x and y coordinate intervals) to cover an area. This is similar to what we can do with blend modes in CSS

The patternUnits attribute defines the coordinate system in use for x, y, width and height properties of the element.

The image SVG element includes images inside SVG documents. It can display raster image files (JPG or PNG) or other SVG files. The behavior for animated GIFs is undefined.

The SVG text element defines a graphics element consisting of text. It’s possible to apply a gradient, pattern, clipping path, mask, or filter to text, just like any other SVG graphics element.

If you include text within SVG outside a text element, it is not rendered. This is different from being hidden by default, as setting the display property will not show the text.

The SVG portion of the example includes the image pattern and the text that we want to use as the mask.

<svg>
  <defs>
    <pattern  id="wood"
              patternUnits="userSpaceOnUse"
              width="400" height="400">
    <image
            xlink:href="http://subtlepatterns.com/patterns/purty_wood.png"
            width="400" height="400" />
    </pattern>
  </defs>
  <!-- 
    The text below will have the background image of the pattern
  -->
  <text y="1.2em">SVG rocks!</text>
</svg>

The CSS sets the dimensions of the SVG element and the text fill, the color inside the element, to use the wood pattern we’ve defined in the SVG.

When we use CSS to style SVG elements we need to be aware that SVG doesn’t use the same selectors, attributes, and values than regular CSS.

svg {
  width: 8em;
  height: 2em;
  font-weight: 900;
  font-size: 5em;
  line-height: 1.2;
  font-family: 'Arial Black', sans-serif;
}

text {
  fill: url(#wood);
}

Clip Path

clipPath defines a clipping path.

The idea is that whatever changes we make to the image will not go larger than the clipping path. In this example, we create to elements inside the SVG a circle and a path with the shape of a heart.

We use the clipping path with the clip-path property.

<svg viewBox="0 0 100 100">
  <clipPath id="myClip">
    <circle cx="40" cy="35" r="35" />
  </clipPath>
 
  <path id="heart" d="M10,30 A20,20,0,0,1,50,30 A20,20,0,0,1,90,30 Q90,60,50,90 Q10,60,10,30 Z" />
 
  <use clip-path="url(#myClip)" xlink:href="#heart" fill="red" />
</svg>

The CSS handles the animation using keyframes. We’re animating the r attribute from CSS. We want the circle to grow into the full size of the clipping element and ignore anything falling outside.

Unfortunately, this example doesn’t work in Firefox (tested with 67 nightly in a Mac) because it doesn’t support geometry properties in CSS. Bug 1383650 is tracking the issue but it doesn’t appear to be a high priority.

The workaround is to remove the clip-path="url(#myClip)" from the use element . We lose the animation but at least we get the color we want to display the clipped element in.

I’m also researching if it’s possible to do this with JavaScript or with CSS @support techniques.

html,body,svg {
  height:100%;
}

@keyframes animateHeart {
  from {
    r: 0
  }

  to {
    r: 60px
  }
}

#myClip circle {
  animation: animateHeart 15s infinite;
}

Conclusion

SVG can be as simple or as complicated as you need it to be. There are other areas that I want to further explore as I move deeper into the things you can and cannot do with SVG as a vector graphic format.