More About SVG Masking — Properties And Attributes

For the last several weeks I’ve been talking about clipping and masking in SVG. Last week I covered the very basics of SVG masking and mentioned I would continue today and talk about some of the additional properties and attributes you can use for greater control of your masks.

These attributes will hopefully make clear the distinction between masks and mask content and I’ll talk about the difference between the two.

One thing I didn’t get to last time was CSS masking. In the clipping part of this series I showed how CSS handles clipping and I’d like to do the same for masking.

Masking with CSS

The situation with masking in CSS is similar to the situation with clipping in CSS. In time, I expect we’ll use CSS more often to mask SVG elements, but at the moment support isn’t quite there. Support for masking is about the same, though a little less than the support for clipping and no browser has full support yet.

Last week’s examples featured a green circle, which I then masked. As a reminder here’s what the circle looks like unmasked.

Just as I did last week, I’m defining a mask as a rectangle with a fill of medium gray (#999). Instead of referencing the mask using the SVG mask property, here I’ve called it using the shorthand CSS mask property.

1
2
3
4
5
6
7
8
9
<svg width="660" height="220" style="outline: 1px solid red">  
 <defs>  
   <mask id="mask-css">  
     <rect x="10" y="10" width="100" height="100" fill="#999" />  
   </mask>  
 </defs>

 <circle cx="110" cy="110" r="100" fill="#9c6" style="mask: url(#mask-css)" />  
</svg>

The result is the same as we saw last week.

You can also create the mask directly in CSS, however, I don’t think you can then mask SVG elements with it at the current time. You can add a mask to an image, which is what I’ve done in the following example.

1
2
<img src="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg"
  style="mask-image: linear-gradient(black, transparent);"/>

Since this code may or may not work in the browser you’re using, here’s an image of what it looks like in Safari (using -webkit-mask-image instead of mask-image).

CSS Masking Example

Again, I don’t suggest you use CSS for masking at the moment given the lack of support, but I wanted to show you how it’s done for when support is there.

Let’s get back to SVG masking and some of the additional attributes you can use to control the mask.

Mask Attributes

Like clipping paths, masks can take several attributes that should be familiar if you’ve been working with SVG at all.

  • x — x-coordinate for the top/left corner of the mask
  • y — y-coordinate for the top/left corner of the mask
  • width — The width of the mask
  • height — The height of the mask
  • maskUnits — Defines the coordinate system for the mask attributes x, y, width, and height
  • maskContentUnits — Defines the coordinate system for the contents of the mask

Both maskUnits and maskContentUnits take the same values. They can be either userSpaceOnUse or objectBoundingBox. These work the same way they did for the clipUnits of a clipping path.

  • userSpaceOnUse — represents values in the current user coordinate system in place at the time when the mask is referenced
  • objectBoundingBox — represents fractions or percentages of the bounding box of the element to which the mask is applied.

You may be wondering what the difference is between them, especially as they take the same two values. The difference is in the name. maskUnits refer to the mask and maskContentUnits refers to the contents of the mask, which has been a <rect> in all the examples to this point.

Mask and Mask Content

If you like back up at the first CSS masking example, it probably seemed like I set the four attributes, x, y, width, and height, but the truth is I didn’t set any of them. The x, y, width, and height set in the example were all attributes of the rectangle inside the mask. In other words they were set on the mask content, but not the mask itself.

Here’s a variation of the example (using the SVG mask property to reference the mask). Here I added x, y, width, and height attributes to the <mask> element. You’ll notice both x and y are 0 and the width and height are 0.5.

1
2
3
4
5
6
7
8
9
<svg width="660" height="220" style="outline: 1px solid red">  
 <defs>  
   <mask id="mask-attributes-1" x="0" y="0" width="0.5" height="0.5">  
     <rect  x="10" y="10" width="100" height="100" fill="#999" />  
   </mask>  
 </defs>

 <circle cx="110" cy="110" r="100" fill="#9c6" mask="url(#mask-attributes-1)"/>  
</svg>

The reason for these values is because the default value of maskUnits is objectBoundingBox, which means the values will be a percent of the bounding box or a number between 0.0 and 1.0.

The default for maskContentUnits is userSpaceOnUse and so the x, y, width, and height of the mask content, the <rect>, are given in pixels.

Here’s the result of the example, which should look familiar.

In the example we just looked at, the location and dimensions of the mask are the same as the mask content. They don’t have to be.

Here I’ve changed the width of the mask (not the mask content) to 0.25. Everything else is the same as the previous example.

1
2
3
4
5
6
7
8
9
<svg width="660" height="220" style="outline: 1px solid red">  
  <defs>  
   <mask id="mask-attributes-2" x="0" y="0" width="0.25" height="0.5">  
    <rect  x="10" y="10" width="100" height="100" fill="#999" />  
   </mask>  
  </defs>

  <circle cx="110" cy="110" r="100" fill="#9c6" mask="url(#mask-attributes-2)"/>  
</svg>

Even though the mask content is a rectangle that’s 100px wide, the mask is 25% of the bounding box of the element that references the mask or 25% of 200px (the diameter of the circle), or 50px. The mask is now half the width it was before.

Here’s the result. The blue outline shows the boundary of the mask content (the rectangle) and the purple line shows the extent of the mask itself.

Of course you don’t have to use the default values for maskUnits of maskContentUnits. Here I’ve set the maskUnits to userSpaceOnUse and maskContentUnits to objectBoundingBox, switching both from their defaults.

Notice that both attributes are set on the mask element. Because I’ve switched the units from their default values, the mask now runs from 10px to 200px in each direction and the mask content (the rectangle) needs to be between 0.0 and 1.0.

1
2
3
4
5
6
7
8
9
<svg width="660" height="220" style="outline: 1px solid red">  
 <defs>  
    <mask id="mask-attributes-2" x="10" y="10" width="200" height="200" maskUnits="userSpaceOnUse" maskContentUnits="objectBoundingBox">  
    <rect  x="0" y="0" width="0.5" height="0.25" fill="#999" />  
   </mask>  
  </defs>

  <circle cx="110" cy="110" r="100" fill="#9c6" mask="url(#mask-attributes-2)"/>  
</svg>

Here’s the result. Notice that this time the mask (purple outline) is the full 100px by 100px in width and height, and it’s the mask content (blue outline) that’s half the height (0.25 of 200px or 50px).

Let’s leave things here for today.

Closing Thoughts

That covers the basics and a little more for working with SVG masks. As I did with clipping paths, I tried to keep the mask and the elements being masked as simple as possible so the concepts could sink in.

Next week and the week after, I’ll offer some examples that go a little further. I’ll show you how to work with paths, text, gradients, and patterns as the mask. I’ll look at multiple shapes for the mask as well as masking a group of elements. Finally I’ll show you how to work with image masks and how to mask images.

Download a free sample from my book, Design Fundamentals.

Leave a Reply

Your email address will not be published. Required fields are marked *