Quick Tip: Perfectly Positioned Plusses

Quick Tip: Perfectly Positioned Plusses

Tutorial Details
  • Topic: CSS positioning
  • Difficulty: Confident beginner
  • Estimated completion time: 10 minutes

Ever seen those thumbnails which, when hovered over, reveal an icon in the middle to suggest what’s about to happen? Ever wondered how the effect is achieved? Ever tried, but didn’t manage to get the icons dead center, especially when your thumbnails weren’t of fixed dimensions? Then this Quick Tip is for you..


I’m talking about thumbnails which you might click to trigger a lightbox, or perhaps a thumbnail which links to a portfolio piece. In any case, it’s a great addition to your site’s usability if you can suggest what’s about to happen when someone hovers over a thumbnail.

This Quick Tip is aimed at those of you who have an understanding of CSS, have more-or-less figured out what positioning is about, and are looking for the perfect excuse to put it to use..


Step 1: Starting Block

Let’s quickly throw some documents together to demonstrate what I’m talking about. Firstly, our html:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>Hover Demo Thingy</title>
		<link rel="stylesheet" href="styles.css" type="text/css" />
	</head>
	<body>
	</body>
</html>

Then we’ll begin our styles.css file with some reset rules. You may well have your own preferred reset methods, but for the time being I’ve used Eric Meyer’s to kick-start our css:

/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}

Next, to give our page a bit of layout structure, here are three columns, within a container:

		<div class="wrapper">
			<div class="col">
			</div><!--end col-->
			<div class="col">
			</div><!--end col-->
			<div class="col">
			</div><!--end col-->
		</div><!--end wrapper-->

And now, of course, we need to add some styles to actually get them behaving as columns within a flexible wrapper:

/*our demo styles*/
html,
body {
	background: #29282e;
}
.wrapper {
	width: 90%;
	max-width: 960px;
	margin: 30px auto;
}
.col {
	width: 27%;
	padding: 0 3%;
	float: left;
}

So there we have them; three columns, each 27% wide, with padding left and right of 3%, and all of them floating neatly in a row. Our wrapper is nicely flexible at 90% of the browser window width (to a maximum of 960px). We’ve also given our body and html a nice, dark background color.


Step 2: Images

It’s time to add some images to the mix. I’ve used some wallpapers from Atelier Olschinsky’s rather inspiring cities collection (grab them from kuvva.com for your desktop..)

Each image is going to be contained within an HTML5 figure element, but wrapped directly by an anchor in order to link it with something (either a lightbox enlarged version, or an external site etc.):

			<div class="col">
				<figure>
					<a class="enlarge" href="">
						<img src="img/cities-07.jpg" alt="city number 7" />
					</a>
				</figure>
			</div><!--end col-->

So we’ll place three of our figures, one for each image thumbnail, within a column of its own.

These images are too big, so to prevent them from bursting out of their columns, let’s give them a maximum width by applying a classic fluid image rule:

figure img {
	max-width: 100%;
}

A good start. We have our fluid layout with three columns, each containing an image which links somewhere.


Step 3: Hover State

Let’s make it clear to users that clicking the images does something. We’ll add a hover state, reducing the opacity of the thumbnail:

figure a:hover img {
	opacity: 0.4;
	filter: alpha(opacity=40); /* IE6-IE8 */
}

Step 4: Icon

Now for the all important icon. We want an icon, placed in the center of the thumbnail, to become visible when the image is hovered over. It can be whatever symbol you like, but it should indicate to the user what’s going to happen. In this demonstration, for the sake of ease, I’m just going to use a + sign to suggest a larger version will be activated.

We’ll add it into the mix using the pseudo element :before:

a.enlarge:before {
	content: "+";
	display: block;
	font-size: 40px;
	line-height: 1em;
	height: 1em;
	width: 1em;
	text-align: center;
	color: #fff;
	font-weight: bold;
	position: absolute;
	z-index: 100;
}

We’ve placed our + as a generated :before element, part of the anchor surrounding the image. We’re using the class “enlarge” to identify the anchors which will need the +. If we need another symbol, we can use another class name.

To begin with we need to dictate the content (our + character) and state that it’s a block level element.

Important! The following rules then determine the dimensions. We’ve said that the font-size is 40px. Then we’ve said that the line-height, the height and the width are all equal to 1em (40px therefore). This has created a square of 40x40px. By setting the text-align to center and the line-height to 1em, we guarantee that the character is sitting smack-bang in the vertical and horizontal center of our square.

The next important rules are the absolute positioning (0px,0px by default) and the z-index which determines the stacking order of our positioned elements. By setting this to 100, we can make sure our other elements sit on top of it. Let’s do that now..

figure img {
	max-width: 100%;
	position: relative;
	z-index: 900;
}
figure a {
	position: relative;
	display: block;
	line-height: 0px;
	text-decoration: none;
}

Here we’ve made sure that the img tags are sitting on top of the + icons by setting the z-index higher than 100. In order for that to take effect we ned to state a positioning type (“relative” in this case). Our anchor also has position:relative which means the + icon is now absolutely positioned against it.

You’ll also notice a few other styles added to the anchor. We’ve made it display as a block, removed any underline decoration, plus given it a line-height of 0px. The line-height is important and if not reset can manifest itself as additional padding at the bottom of the element. We’ve now made sure that the anchor fits snugly around the image.

Our icons are actually always present, but they only become visible when the image covering them is hovered over.


Step 5: Proper Positioning

At the moment, our icons are positioned as default in the top left of our anchors. We need them in the center of the thumbnails, irrespective of how big the thumbnails are. Let’s then position them 50% from the left and 50% from the top. Job done, right?

a.enlarge:before {
	content: "+";
	display: block;
	font-size: 40px;
	line-height: 1em;
	height: 1em;
	width: 1em;
	text-align: center;
	color: #fff;
	font-weight: bold;
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 100;
}

Hmm. Not really. The icon’s nowhere near the center of the thumbnail.. That’s because elements are aligned in relation to their top left corner. Look again:

To compensate for the positioning we have to shift it half its height up and half its width left. We used ems earlier to determine the dimensions (1em = 40px), so let’s now use 0.5em (half the square’s width) to do the shifting. This way, whatever we change the font-size to, all the measurements will remain proportional. Thanks to Gabri for pointing out the use of ems!

a.enlarge:before {
	content: "+";
	display: block;
	font-size: 40px;
	line-height: 1em;
	height: 1em;
	width: 1em;
	text-align: center;
	color: #fff;
	font-weight: bold;
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 100;
	margin: -0.5em 0 0 -0.5em;
}

To do that we apply a negative margin. -0.5em on the top and on the left will do the job. Think of it as having created a vacuum, into which our element is sucked.

Bingo! Our + icon is perfectly positioned in the center of our thumbnail. Try resizing the browser, it’ll stay exactly dead-center.


Why not take the effect further?

There’s bags of potential for a technique like this:

  • Employ the websymbols font and jazz your icons up a bit.
  • Apply different classes to your thumbnails, depending on the icon you want to display.
  • Why not add CSS transitions to smooth the hover effect?

Conclusion

To seasoned CSS-ers this is a very straight-forward trick, but if you’ve never considered positioning like this before I hope this Quick Tip has been helpful.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://gabri.me Gabri

    Since you are using EMs already it’s better to use it too on the margins so in case you changed the font-size at any point later everything will be intact.

    for example: you decided to make the font-size 20px, now 1em = 20px but the margins will still be -20px but if you changed the margins to (margin:-0.5em 0 0 -0.5em;) then it will be -10px instead “cause now it’s relative to the font-size” & it be still perfectly centered without the need for further modification in your code.

    • http://www.snaptin.com Ian Yates
      Author

      Good point! An oversight on my part – I’ll update the tutorial to reflect that. Thanks :)

  • Chris

    I would have used a list instead of div columns, but whatever.

    • http://www.snaptin.com Ian Yates
      Author

      It was just quick mockup – you can use whatever you want for the actual page structure.

  • MAHDI

    Without using jQuery techniuque? Yeah it’s better.

    Question: Can I change the + icon with text or try something else

    PS: Could you please change the link of “Tutorial Template”?

    Thanks Ian!

    • http://www.snaptin.com Ian Yates
      Author

      You can use whatever you like! The WebSymbols from JustBeNiceStudio are perfect – link icon, magnifying glass, full-screen icon, whatever (check out the demo – I’ve updated it to show what I mean).

      You could alternatively use a text string (just make sure you take the dimensions into account) or even rely on a good old-fashioned background image :)

      PS) Yep, sorry about that link, it was dead for some reason (?) Link updated..

      • MAHDI

        This technique reminds me of Dribbble When you move the mouse above a thumbnail.

        So I just need to change the opacity of the thumbnail

        Thanks for updating the link!

  • Pingback: Quick Tip: Perfectly Positioned Plusses | Shadowtek | Hosting and Design Solutions

  • Techeese

    Am I the only one seeing on hover the image thumbnail enlargest a bit?

    • MAHDI

      Techeese, Yes it is, 1px left in the right side

      Ian, I see that you’ve updated the demo page. looks pretty amazing, especially the Alternative icon one!

    • http://www.snaptin.com Ian Yates
      Author

      I see it too (though only in Firefox). The images are actually bigger than they’re being displayed – they’re restricted to the size of their container divs and the browser is therefore doing the scaling. Firefox seems to mess up the rendering of the scaled .png image when an opacity is applied to it.

      It’s a known issue, here’s how Mozilla describe it:

      Summary: png aliasing on opacity changes < 1 → image opacity changes result in odd alpha / invalidation for scaled image.

  • Valstorm

    Note that IE8 only has partial support for :before and :after pseudo tags. IE7 is completely unsupported.

    Any objects added using the :before pseudo would have to be added to DOM by javascript or manually added for IE7 and below – not sure what the current stats around but last time I checked they account for around 5 – 10% of global use.

    Alternatively you could use the following markup:

    – center center background image with graphic for hover state
    – drop opacity on :hover to reveal the background of the parent div

    It’s a reverse way of thinking about it but visually it would provide almost the same result.

    • Valstorm

      Comments wouldnt allow the markup in the text.

      Use an image tag inside and anchor tag basically.

    • http://www.snaptin.com Ian Yates
      Author

      Hey Valstorm,

      You’re right (though IE8 should be fine with this), and adding such a fallback with an IE7 specific stylesheet wouldn’t be a problem.

      The nice thing about this effect is that it degrades gracefully: IE7 users won’t see the icon, but they’ll still have a perfectly functional hover effect.

  • Pingback: Tweet-Parade (no.5 Jan-Feb 2012) | gonzoblog.nl

  • Nikita Belousov

    Thank you!!!! It’s very useful!!))

  • http://www.monochrom-fotoart.de mono

    Yay, nice tutorial at the right time!!! Thanks a lot!

  • Pingback: Quick Tip: Perfectly Positioned Plusses | Graphfucker

  • http://www.web-cooperative.com Web Cooperative

    Pretty nice effect used on a lot of sites these days. Siiimple does something similar.

  • Pingback: 15 Time Saving Tutorials for Web Developers | PHP Developer Resource

  • Pingback: Quick Tip: Perfectly Positioned Plusses | Webdesigntuts+ » Web Design