A common film effect used to transition scenes in movies of the 1920’s to 50’s, the iris wipe – a rapidly shrinking circle or dot that acts as a mask – is relatively rare today, except in cases it is used to evoke a feeling of nostalgia: modern examples would include the original Star Wars and Looney Tunes cartoons. Using an iris wipe on your site can create that same sense of fun, but it may not be immediately apparent as to how to make one in pure .

While Webkit has some interesting CSS image mask proposals, and the effect is, in theory, achievable with , I wanted to use something that would work across all modern browsers today. It occurred to me that border-radius could be used together with width and height, much as I’ve shown you how to use the property to create .

For this example, I've hosted the code at CodePen, a great new web development sandboxing site. This will also make it easier for you to play with the and CSS, if you wish to.

The markup is simplicity itself:

<a href=# class=iris><span></span></a>

Both elements share many qualities, and those that don’t apply to the span will be ignored or overwritten by later declarations. We’re going to set both elements to block, together with the width and height:

a.iris, a.iris span {
	display: block;
	background-image: url(mars.jpg);
	width: 150px; height: 150px;
	border-radius: 50%;
	color: #000;
	text-decoration: none;
	background-position: center;
	background-size: fit;
}

The border-radius effectively cuts the elements into perfect circles. For the example shown on the right we’re using two images: one of Mars, and another of Marvin The Martian. We’re going to apply these pictures as multiple background images to the a tag:

a.iris {
	position: relative;
	background: url(marvin.png),
		url(mars.jpg);
	border: 5px solid black; 
}

Remember that when specifying multiple image backgrounds the first image in the declaration appears on top by default. In our case, that first image is a 24-bit PNG, so we can see around it to the background image underneath. Above the link, we have a span with a lone background image, as specified in the first declaration.

Now that everything is held together and aligned properly, we’ll specify some text to appear below the link, using a pseudo-element:

a:before {
	content: "Where's the kaboom?";
	position: absolute;
	text-align: center;
	top: 170px; 
	opacity: 0;
	transition: 1s all linear;
	display: block;
}

Now, the interesting part. We’re going to reveal the composite image in the link by decreasing the width and height of the <span:

a.iris:hover span {
	width: 0px; height: 0px;
}

That works perfectly well when the transition is instantaneous, but what we want is for the span to shrink towards the center of the link over time. So we’ll add a transition to the default state of the span:

a.iris span {
	transition: .5s ease-in all;
}

If you tried this, you’d see the problem immediately: the <span> shrinks towards the top left corner of the link. We’re back to the problem of trying to vertically align elements within containers, which is a perennial CSS boondoggle. What’s worse is that none of the standard solutions apply: we can’t use table-cell and vertical-align: center; since Firefox won’t shrink the size dynamically if we do so. And we can’t use margin to push the inner element down from the top, as that distance will be changing all the time as the <span> shrinks in size.

You might suggest that we could modify the background image itself by using background-size, but that won’t achieve the effect we are after: we want to keep the images the same size while masking them, not shrink the pictures.

What we’ll use instead is something relatively new to CSS: the : the following will give us the much-sought-after vertical and horizontal centering we desire.

a.iris {
	position: relative; 
	display: flex;
	justify-content: center;
	align-items: center;
	background: url(marvin.png), url(mars.jpg);
	border: 5px solid #000;
	background-position: center;
}

Finally, we’ll set the text below to be visible.

a.iris:hover:before {
	opacity: 1;
}

We can also use this technique to create navigational buttons, as shown in the top left corner of this article. That markup is very similar to the code above, so it is presented here without further analysis; the primary difference is that the inner <span> now has a background color, and changes opacity as it shrinks.

a, span {
	display: block;
	background-color:rgba(4,78,127,1);
	width: 120px; height: 120px;
	border-radius: 50%;
	color: #000;
	text-decoration: none; 
	text-align: center;
}
a { 
	background: url(pariah-kite.jpg);
	border: 2px solid black;
	background-size: cover;
}
span {
	transition: .5s ease-in all;
	font-size: 50px;
}
a:hover span {
	background-color:rgba(4,78,127,0.3);
	width: 0px; height: 0px;
}
a:after {
	content: "⬅";
	position: absolute;
	top: 65px; left: 30px;
	color: rgba(255,255,255,0.8);
	font-size: 60px;
	line-height: 0;
}
a:hover:before {
	opacity: 1;
}
a:before { 
	content: "Learn more about hawking";
	position: absolute;
	text-align: center;
	top: 130px; opacity: 0;
	transition: 1s all linear;
	display: block;
}

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.