WebKit Image Wipes

Chris Coyier //

It's not "spec," but WebKit browsers support image masks. If you are familiar with Photoshop, they work like that. You declare an image to use as as mask. The black parts of that image hide what it is over, white parts of that image show what is underneath, gray is partially transparent. So if you had this image:

<img src="orig.jpg" alt="trees" class="circle-mask">

And you had this image you created as a mask:

You'd apply it to the image in CSS like:

.circle-mask {
  -webkit-mask-box-image: url(mask.png);
}

And this would be the result:

You Don't Need Actual Images

The first trick we're going to utilize here is that the image we delcare for the -webkit-mask-box-image doesn't need to be an actual graphic image. Instead we can use -webkit-gradient to create that image. Yes, we could just make an image that is a gradient as well, but creating the gradient mask programmatically means that it's far easier to adjust on the fly and requires one less HTTP request.

-webkit-mask-position: 0 0;
-webkit-mask-size: 200px 200px;
-webkit-mask-image: -webkit-gradient(linear, left top, right bottom, 
   color-stop(0.00,  rgba(0,0,0,1)),
   color-stop(0.45,  rgba(0,0,0,1)),
   color-stop(0.50,  rgba(0,0,0,0)),
   color-stop(0.55,  rgba(0,0,0,0)),
   color-stop(1.00,  rgba(0,0,0,0)));

In the above CSS, we've created a 200px by 200px image which fades from fully opaque in the top left and fading and about half-way point at a 45deg angle, fades to fully transparent. That would look a little something like this:

Moving The Mask

Notice we set the position of the mask with -webkit-mask-position. Because we can set the position, we can move the position. We could move it on a :hover -

.circle-mask {
	-webkit-mask-position: 0 0;
}
.circle-mask:hover {
	-webkit-mask-position: -300px -300px;
}

Or we could use a -webkit-animation to automatically move that mask.

@-webkit-keyframes wipe {
	0% {
		-webkit-mask-position: 0 0;
	}
	100% {
		-webkit-mask-position: -300px -300px;
	}
}
.circle-mask {
	-webkit-animation: wipe 6s infinite;
	-webkit-animation-delay: 3s;
	-webkit-animation-direction: alternate;
}

Creating The Wipe

I'm sure all you smarties have already put all this together. The idea is that we have one image on top of another image. The image on top gets the mask, and then we move the mask as needed.

<div id="banner">
	<div><img src="images/banner-1.jpg" alt="Skyline 1"></div>
	<div><img src="images/banner-2.jpg" alt="Skyline 2"></div>
</div>
#banner {
	width: 800px;        /* Size of images, will collapse without */
	height: 300px;
	position: relative;  /* For abs. positioning inside */
	border: 8px solid #eee;
	-webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.75);
}

#banner div {
	position: absolute; /* Top and left zero are implied */
}

/* Second one is on top */
#banner div:nth-child(2) {
	-webkit-animation: wipe 6s infinite;
	-webkit-animation-delay: 3s;
	-webkit-animation-direction: alternate;
	-webkit-mask-size: 2000px 2000px;
	-webkit-mask-image: -webkit-gradient(linear, left top, right bottom, 
			color-stop(0.00,  rgba(0,0,0,1)),
			color-stop(0.45,  rgba(0,0,0,1)),
			color-stop(0.50,  rgba(0,0,0,0)),
			color-stop(0.55,  rgba(0,0,0,0)),
			color-stop(1.00,  rgba(0,0,0,0)));
}

Demo and Download

In the download, there is another example where the wipe goes horizontally instead of at an angle, and happens using -webkit-transition rather than animation on a hover event.

View Demo   Download Files

More Than Two?

I spent more time than I probably should have trying to see if I could get the animation to wipe three images in succession. It's kind of possible but I wasn't able to get it smooth and consistent as I would have liked, so I scrapped it. I'm still fairly sure it's possible, probably using two different animations with different delays or the like. If you try it and get it worked, do show!

More

Check out the announcement from 2008 for more information about the masks themselves. There are useful bits to know in there, like the mask images can stretch (like full page backgrounds) and repeat. It actually works a lot like border-image, with the nine-box system for stretching/repeating.

Credit

I stole this idea from Doug Neiner who showed me a little demo of the idea. Posted with permission.