Annotation Overlay Effect with CSS3

A tutorial about how to create an overlay effect to show some more details of an item or image. The effect is CSS-only and uses a combination of the :checked pseudo-class with the sibling combinator.

Annotation Overlay Effect with CSS3

In this tutorial we’ll create a little overlay effect with CSS using a combination of the :checked pseudo-class with sibling combinators. The idea is to make an image or element clickable and transition to an overlay-like state that will show us some annotation boxes.

The theme preview images used in this tutorial are by talented Ana Segota and you can purchase her themes and templates here.

The beautiful arrow icons are by Alessio Atzeni and you can find them here.

Please note: the result of this tutorial will only work as intended in browsers that support the respective CSS properties.

The Markup

Our structure will consist of a part for some title and description, and a preview part. The preview part will have the overlay effect. The idea is to add a checkbox, an image and a division for the annotations, containing spans. The trick is to actually put the checkbox on top of the other elements, so that it remains clickable. It needs to stay first in the structure though because we want to be able “to reach” its siblings, the image and the annotations division:

<div class="ao-item">
	<div class="ao-details">
		<h2>Some title</h2>
		<p>Some description</p>
	</div>
	<div class="ao-preview">
		<input type="checkbox" id="ao-toggle" class="ao-toggle" name="ao-toggle" />
		<img src="images/image01.jpg" alt="image01" />
		<div class="ao-annotations">
			<span>Full Localisation Support</span>
			<span>Custom Image Widget</span>
			<span>Blog and Contact Widgets</span>
			<span>Easy Theme Options</span>
			<span>4 Footer Widget Columns</span>
		</div>
	</div>
</div>

There can be any number of spans. We will position each one individually.
Let’s take a look at the CSS.

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The CSS

Note that we will exclude vendor prefixes. You will of course find them in the files.
The division with the class ao-item will have a width of 80% because we want the whole thing to be fluid:

.ao-item {
	width: 80%;
	margin: 0 auto;
	padding: 35px 0;
	position: relative;
	clear: both;
}

The two inner divisions will be floating, so let’s clear some floats with this great technique:

.ao-item:before,
.ao-item:after {
    content:"";
    display:table;
}

.ao-item:after {
    clear:both;
}

.ao-item {
    zoom:1; /* For IE 6/7 (trigger hasLayout) */
} /* from CSSTricks: http://css-tricks.com/pseudo-element-roundup/ */

Let’s style the details part with the title and the description. We’ll make it float right and give it a width of 40%. We’ll also add a left padding which will not cause us any trouble because we’ve applied box-sizing: border-box to all our elements in the normalize.css file. So this will ensure that the division is really 40% wide and the padding is “inside” of that and not added to it:

.ao-details {
	float: right;
	width: 40%;
	padding-left: 20px;
}

Then we’ll add some styling to the text elements:

.ao-details h2 {
	color: #498EA5;
	margin-top: 0;
	text-shadow: 1px 1px 1px rgba(255,255,255,0.5);
	padding-bottom: 10px;
	box-shadow:  
		0 1px 0 #DFDEDC, 
		0 2px 0 rgba(255,255,255,0.5);
}

.ao-details p {
	color: #999;
	text-shadow: 1px 1px 1px rgba(255,255,255,0.8);
	line-height: 22px;
}

.ao-details p a{
	font-weight: bold;
	color: #498EA5;
}

.ao-details p a:hover{
	color: #2A3344;
}

The preview division will be a bit bigger and floating left:

.ao-preview {
	width: 60%;
	float: left;
	position: relative;
}

Now we’ll style the image. In order to make it responsive, we’ll give it a max-width of 100%. This will ensure that it will be contained in the parent division. The image will have a transition. The idea is to scale it down a bit, once we click on the associated checkbox:

.ao-item img {
	margin: 0 auto;
	max-width: 100%;
	display: block;
	opacity: 0.8;
	box-shadow: 1px 1px 10px rgba(0,0,0,0.2);
	transition: all 0.3s ease-in-out;
}

The annotations division is our overlay and we’ll place it absolutely. We’ll make it invisible by setting the opacity to 0. It will also have a transition: we want it to scale it up and make it become opaque once we click on the checkbox.

.ao-annotations {
	width: 100%;
	height: 100%;
	position: absolute;
	top: 0px;
	left: 0px;
	background: rgba(33,62,68,0.3);
	box-shadow: 1px 1px 3px rgba(0,0,0,0.05);
	opacity: 0;
	z-index: 5;
	transform: scale(0.8);
	transition: all 0.3s ease-in-out;
}

The annotation spans will be of absolute position (we’ll set each of the tops and lefts) and we’ll give them a min-width of 140 pixel since the width is in percentage. The transition effect will be to scale down and appear (opacity: 1):

.ao-annotations span {
	display: block;
	position: absolute;
	padding: 10px 25px;
	width: 33%;
	min-width: 140px;
	text-align: center;
	background: rgba(255,255,255,1);
	color: rgba(20,40,47,0.9);
	font-size: 16px;
	font-style: italic;
	text-shadow: 1px 1px 1px rgba(255,255,255,0.9);
	box-shadow: 0px 1px 4px rgba(0,0,0,0.2);
	opacity: 0;
	transform: scale(1.3);
	transition: all 0.3s ease-in-out;
}

Each annotation span is going to have a little arrow and we’ll add it using the pseudo-class :after.

.ao-annotations span:after {
	position: absolute;
	background: transparent url(../images/arrow.png) no-repeat center center;
	width: 32px;
	height: 33px;
	top: 50%;
	left: 100%;
	margin: -16px 0 0 -16px;
	content: '';
}

Two of our spans will have the arrow on the left side:

.ao-annotations span:nth-child(3):after,
.ao-annotations span:nth-child(4):after {
	left: auto;
	right: 100%;
	margin: -16px -16px 0 0;
	background-image: url(../images/arrow_left.png);
}

Now we’ll set the positions for each one of the spans. We’ll use percentages again so that the positioning still makes sense, when we resize things:

.ao-annotations span:nth-child(1) {
	top: 5%;
	left: 5%;
}

.ao-annotations span:nth-child(2) {
	top: 20%;
	left: -13%;
}

.ao-annotations span:nth-child(3) {
	top: 37%;
	right: 2%;
}

.ao-annotations span:nth-child(4) {
	top: 53%;
	right: -8%;
}

.ao-annotations span:nth-child(5) {
	bottom: 18%;
	left: -4%;
}

Let’s take care of that checkbox now. The trick is to put it on top of all the other elements and set its height and width to 100% meaning that it will occupy all the division, so that we can click anywhere to trigger the effect. It will be “hidden” since we set the opacity to 0. But it’s still there, so we can click on it. The z-index needs to be higher than the one of the other elements, so, just to make sure, we’ll set it very high:

input.ao-toggle {
	width: 100%;
	height: 100%;
	position: absolute;
	top: 0px;
	left: 0px;
	margin: 0;
	padding: 0;
	opacity: 0;
	z-index: 100;
	border: none;
	cursor: pointer;
}

And now we will define what happens to the siblings when we click on the checkbox. The image will scale down, change its box-shadow and become opaque:

input.ao-toggle:checked + img {
	box-shadow: 1px 1px 6px rgba(0,0,0,0.2);
	opacity: 1;
	transform: scale(0.8);
}

Since we can’t use img:hover anymore (remember, the checkbox is on top of everything else), we’ll use the hover on the checkbox input to trigger the hover effect of the image:

input.ao-toggle:hover + img{
	opacity: 1;
}

The overlay with the class ao-annoations and its spans will scale to 1 and become opaque:

input.ao-toggle:checked ~ .ao-annotations,
input.ao-toggle:checked ~ .ao-annotations span{
	opacity: 1;
	transform: scale(1);
}

To add a little cherry on top, we’ll make each span appear with a delay:

input.ao-toggle:checked ~ .ao-annotations span:nth-child(1) {
	transition-delay: 0.3s;
}

input.ao-toggle:checked ~ .ao-annotations span:nth-child(2) {
	transition-delay: 0.4s;
}

input.ao-toggle:checked ~ .ao-annotations span:nth-child(3) {
	transition-delay: 0.5s;
}

input.ao-toggle:checked ~ .ao-annotations span:nth-child(4) {
	transition-delay: 0.6s;
}

input.ao-toggle:checked ~ .ao-annotations span:nth-child(5) {
	transition-delay: 0.7s;
}

Last, but not least, we’ll add a media query to remove the float for the main divisions and decrease the font size for the annotation spans:


@media screen and (max-width: 730px){
	.ao-item .ao-details,
	.ao-preview { 
		float: none; 
		width: 100%;
		padding: 0;
		text-align: left;
	}
	.ao-annotations span {
		font-size: 11px;
	}
}

And that’s it! I hope you enjoyed this tutorial and find it inspiring!

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

👾 Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

Feedback 21

Comments are closed.
    • Yes, you are of course right, that would have been a wiser choice 🙂 It can simply be replaced. Thanks a lot for you feedback! Cheers, ML

  1. It works on IE 7-9 which is great. It might not have the transition effect but it still works. This would work great on a portfolio site. Its one of those things that you say to yourself why didn’t I think of that. Great work Mary! I will be using this one for my site.

    • It doesn’t work in IE < 9. Maybe you've installed chrome frame, or you just had IE7 browser mode w/ IE9 standards.
      About the result I really think It's great and beautiful, as always ;).

  2. Love this!!!
    Beautiful and responsive interaction and loads of potential applications! plus it falls back nicely in IE.
    great article, I keep being amazed by the amount of stuff you guys come up with using pure CSS/HTML! 🙂

  3. Nice idea, thanks for sharing,
    it looks good.
    By the way, mary lou even too 😉

  4. Why you are not use JS? Whether the use of radio is better of use JS? This is not semantic.
    And when you write simple plugin, then uses this is much easier (for example set position in plugin options)

  5. Another beautiful tutorial, love it ;). You have amazing ideas, thanks for the inspiration 🙂

  6. Looks pretty nice,
    can’t seem to get it working though in Firefox 12 on Ubuntu Release 12.04 (precise) 64-bit, whereas in the note the FF icon is highlighted
    Any ideas?

    • It isn’t working with Firefox 13 on Ubuntu 11.10 64bit either but seems to work with Firefox on both PC & Mac fine for me. If you find a solution or workaround I would love to hear it!
      I also noticed it doesn’t work on Android but image that is a whole other issue entirely.

  7. This is one of the best tutorial site, I have came across. Great Tutorial. Thanks

  8. Awesome!!!! really love Codrops!!! I’ve a suggestion:

    It would be possible to have the “Download source” link in the “View Demo” page?

    Thanks