By Spencer Norman

Image Masking in CSS

What if CSS allowed us to specify an image or shape that would include only the content that existed within the shape?

Good News: There is such a thing and it’s now on the standards-track in the official W3C CSS spec
Bad News: IE and Firefox* don’t support it (yet)
Good News: But webkit does! (partially) and there is a workaround in firefox.
(note: Firefox does have good SVG support and with a little extra work you can have CSS image masking working in both firefox and webkit based browsers but it’s more complicated in firefox, we will get into that.)

The Old Way


We’ve been able to create round “masks” for a while now in CSS with the border-radius property. Essentially what I would do to create a round image would be to set the border radius to something ridiculous like 1000px.

The effect would look like this:


Now, this works as long as your image is square such as the one above, but it fails miserably when your image is not square.


It also doesn’t allow for any shape other than “round” which is pretty limiting. Round is nice to have, and it’s nice that you don’t have to create round images, but what would be even better would be if we could mask images with any shape regardless of the original shape of the images.

The New Way

Step 1 – Create SVG

We need to create a compatible SVG. SVGs are Scalable Vector Graphics. If you are new to vector art, essentially what this means is that we are defining shapes (vectors), and that because the shape is defined rather than the pixels, we can scale this graphic to any size without loss of quality. You should create an SVG that is version 1.1. I used Adobe Illustrator (CS4) to create mine, but any program that allows you to export images as SVG should work.

I created a SVG of our logo for this post: after exporting it from AI, here is what the file looks like. As you can see it’s essentially two paths (the two halves of our logo) with fill colors defined. There are some other SVG definition xml, and doctype declarations, but the parts that defines the shape are all between the <svg></svg> tags.

If you are just working with webkit browsers, this is enough. Take this file. Upload it to your server, and call it with -webkit-image-mask: url({your-image-path); and the mask will work. However I want to make this work with Firefox as well (IE is not ready for the future yet). So we will have to do a bit more work.

Step 2 – Add a mask to the SVG

To make this svg work as a mask with firefox we have to actually do the work of defining a <mask> within our svg. I haven’t found a way to do this within Illustrator yet, so I open up the .svg file in my favorite text editor: Sublime Text 2 and add the necessary code for the mask. Essentially you need to copy the shape code (path in my case) and add it to a mask object. Specifically take note that the mask has an id. You will need that in your css for firefox to play nice.

It’s also worth noting that if you want a perfectly transparent mask then you need to set the fill color in the mask to white.

Step 3 – Write some CSS

Now we can define the css. Set the width and the height to whatever is correct for your mask. This will also help the images to degrade in IE to a square that takes up the same amount of space.

Step 4 – Add class to HTML elements

All that’s left to do now is include the class on whatever elements we want to mask. Here are the two images we used the border-radius trick on earlier.

yobel-thumb yobel-thumb

And poof. We have vector masks that are controlled by CSS. As proof of concept, here’s a paragraph of text that has been masked over.

Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of “de Finibus Bonorum et Malorum” (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, “Lorem ipsum dolor sit amet..”, comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from “de Finibus Bonorum et Malorum” by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.

So now, for any project where you don’t care if IE doesn’t have all the features you can use VECTOR MASKS! Photos, maps, videos, etc can all take the shape you always dreamed about.

Have fun out there kids.


  1. These masks are not click blocking meaning that if you have mouse events that trigger when you click or hover while over the element they will still trigger if you are over the element but outside of the mask.
  2. In webkit using the -webkit-image-mask, you can use transparent .pngs as well as .svgs. This does not work in firefox with the mask, but it may be part of the standards-track with the WC3, not sure.
  3. If there is interest, I’ll write up a post about how I exported the .svgs from illustrator. I don’t have inkscape or any other vector graphic programs, but if anyone wants to write a tutorial on getting svgs from other programs, I’d gladly link or feature them here.
  4. As of the time this was published -webkit-image-mask is supported in the following browsers: Safari 4.0+, Chrome 8.0+, iOS Safari 3.2+ and Android browser 2.1+, and mask is supported in Firefox 3.5+ (according to the Mozilla Developer Network)
  5. Christian Schaefer writes at length about some of the more technical details at The Nitty Gritty and has some workarounds for IE if you don’t care about a purely CSS solution. Specifically he pioneers a way to use the chroma filter in IE 4-9 to mask images.