How to make this horizontal list with top images on each a element using sprites?

Here’s the indented result:

Here’s a test with no swapping images

If we replace the background image with the “swappable” sprite technique image, like the one here:

I’m thinking that, perhaps, if we give more space between the states, this will work, BUT in order to make a menu like the intended one, let me ask this first: Am I on the right track ? If not, what would be a proper/common way for achieving this?

Please advice,
mem

You can place all of the images in that menu in one sprite image. You just have to set a defines space for the image to appear that’s just the right size to show only as much as you want of the image at any one time, and then shift the image position each time, such as background: url(image) no-repeat -40px -200px;.

thks. The thing is, those buttons, will / should appear or not , regarding the user permissions, so, I believe, I should build them individualy.

Any suggestion?

thks again.

Like Ralph suggested, you can use a single sprite, however, you don’t need the middle row as it’s identical to the first row, unless I’m not seeing correctly? If the first and second row is identical, then just use two rows.

For each link, you’ll need a fixed height and width for the bg image, otherwise you’ll see parts of the sprite you don’t want. The code below is just an example of the logic you can apply. To make it work, you’ll likely want an extra element such as a span to better style the text and visually separate it from the background image.

E.g.:

#nav a:link, #nav a:visited {
background:url(sprite.png) no-repeat 0; /*  need to declare bg image once for all nav links to follow */
}

And for the :hover, :focus states:

#nav a:hover, #nav a:focus {
background-position: 0 -100px;
}

Then for the single links:

#nav a.dashboard {
background-position: 0 0; /* not really needed since it's the first image link */
}

#nav a.produtos {
background-position:200px 0; /* left position = width of 1st sprite */
}

#nav a.initiativas {
background-position:300px 0; /* left position = width of 1st + 2nd sprite */
}

[and so on…]

By giving each link a class, it’s easy for you to exclude a link based on a set permission. It does not matter whether you use the entire sprite (all nav links) or not, the position of the images will always remain the same as the dimensions and distance from A to B to C are constant.

That’s a programming issue, which shouldn’t affect the CSS at all. Perhaps you can set different classes to appear depending on the permissions, but that will happen server-side.

Thank you both. I was not getting that we could do this using a single image, but if we give each item a specific width or height, indeed makes sense.
I still believe several images instead of just one single image is better on this case at least. If the users have a larger font size defined for example, it seems (at this first glass) that we may avoid problems if we opt for 1 image per element.
Another advantage of using a separate files instead of one, could be that of allowing our content to drop / shrink if we choose to use media queries later on for example. (so I believe).

If what I’ve stated isn’t correct please, say so. :slight_smile:

Thanks a lot, I will try to apply your suggestions right away.

You can still use a sprite. By using an extra element, like a span (for the bg image) and applying a fixed width and height to it, you don’t need to have fixed dimensions on your li or a, ergo you can make it fluid, elastic, fixed, or apply no width at all.

Yes as Maleika said I prefer to use a separate element for the sprite image as it can be sized to fit and will not reveal more images if the page is resized. It means an extra span in the html but it makes the whole thing so much easier to work with. If Ie8+ only support was needed then you could use :before with generated content to place the icons (assuming that you still had real text content to identify the link as generated content should only be used for non important information).

If we shrink the screen to a minimum width, the buttons, that now appear side by side, should appear vertically on top of each other.
You are all saying that, even if that is the case, we can still use this one single sprite technique because, it will be a question of position the background accordingly.
By changing the css accordingly when the vertical layout arrives. Is that it ?

If so. Ok.

I still don’t understand the span part. Why do we need a span ? I don’t mind adding a span, really - I’m just trying to understand the need.

Here’s what I’m thinking (directly written here):

The markup will be something like:


<ul>
 <li><a href=""><span>the text here</span></a></li>
 <li><a href=""><span>the text here</span></a></li>
</ul>

And then on the CSS side of things something among those lines ?

ul li a span {
  display: block; /*so that width and height could be applied (or only height?)*/
  width: 20%;
  height: 85px;
  background: url(oneSingleImageSprite.png) no-repeat 0;
  border-right: 1px solid #999;
}

ul li a.first span {
  border-left: 1px solid #999;
}

ul li a:hover span {
  background-color: #999;
}

ul li a:active span {
  background-color: #3f46b;
}

/* then the classes for each button... */
ul li a:hover span.dashboard {
 background-position: 0 -170px;
}

ul li a:hover span.password {
  background-position: 0 -370px;
}

(:

I’d use the empty span for the sprite like so:

(Rough example using colours to represent the images).


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
ul {
	margin:0;
	padding:0;
	list-style:none
}
ul li a, ul li span { display: block; /*so that width and height could be applied (or only height?)*/ }
ul li span {
	height:40px;/* height and width of icon */
	width:40px;/*   "  " */
	background: url(oneSingleImageSprite.png) no-repeat 0;
	margin:auto;
	background-color:yellow;
}
ul li {
	float:left;
	border-right: 1px solid #999;
}
ul li a {
	text-decoration:none;
	padding:0 10px;
}
ul li.first { border-left: 1px solid #999; }
ul li a:hover { background-color: #999; }
ul li a:active { background-color: #3f46b; }
/* then the classes for each button... */
ul li.dashboard a:hover span {
	background-position: 0 -170px;
	background:red
}
ul li.password a:hover span {
	background-position: 0 -370px;
	background:blue;
}
</style>
</head>

<body>
<ul>
		<li class="first dashboard"><a href=""><span></span> The text here</a></li>
		<li class="password"><a href=""><span></span> The text here</a></li>
</ul>
</body>
</html>


Thanks a lot. I’ve changed the heights and widths to work with EM, and we can have that same menu on an fluid layout.

Again, thank you all for your help. :slight_smile:

Paul’s example misses showing you how to handle your top/bottom padding, and more important sliding the image sideways without resorting to a giant mess of CSS declaring background-position three times for EVERY menu item. (assuming we’re talking one image for the whole MENU, which is the efficient approach).

The trick i’d use for that is using overflow to chop it off, and to add the padding to the top of the image… for example if you had 8px padding top/bottom and a 48x48 image, I’d store them as a grid of 48x56 (stick with multiples of 8, computers work better with them, as does the png compression) for a single image of 8x3 tiles working out to a 384x168 file. I would also suggest DITCHING alpha transparency and pre-compositing the images to save bandwidth, cross browser headaches, and to skip throwing some idiotic script at legacy IE just to make the dumbest bloated version of PNG work.

So for markup (pretty much what Paul did except with more relevant classes)


<ul>
	<li class="home current">
		<a href="#">
			<span></span>
			Home
		</a>
	</li>
	<li class="produtos">
		<a href="#">
			<span></span>
			Protudos
		</a>
	</li>
	<li class="iniciativas">
		<a href="#">
			<span></span>
			Iniciativas
		</a>
	</li>
	<!-- etc, etc --->
</ul>

with this for CSS:


/* null margins and padding to give good cross-browser baseline */
html,body,address,blockquote,div,
form,fieldset,caption,
h1,h2,h3,h4,h5,h6,
hr,ul,li,ol,ul,
table,tr,td,th,p,img {
	margin:0;
	padding:0;
}

img,fieldset {
	border:none;
}

#menu {
	overflow:hidden; /* wrap floats */
	zoom:1; /* trip haslayout, wrap floats IE */
	list-style:none;
	border-left:1px solid #CCC;
}

#menu li {
	display:inline;
}

#menu a {
	float:left;
	width:110px;
	overflow:hidden;
	padding:56px 0 8px;
	border-right:1px solid #CCC;
	text-align:center;
}

#menu a span { /* need to say 'a' for specificity legacy IE */
	position:absolute;
	top:0;
	left:50%;
	margin-right:-24px;
	height:56px;
	width:48px;
	background:url(imageSprites.png) 0 0 no-repeat;
}

#mainMenu .current a {
	background:#F0F0F0;
}

#mainMenu .current a span {
	top:-56px;
	height:112px;
}

#menu a:active,
#menu a:focus,
#menu a:hover {
	background-color:#8CF;
}

#menu a:active span,
#menu a:focus span,
#menu a:hover span {
	top:-112px;
	height:168px;
}


#mainMenu .home span {
	background-position:0 0;
}

#mainMenu .produtos span {
	background-position:-48px 0;
}

#mainMenu .iniciativas span {
	background-position:-96px 0;
}

#mainMenu .formacoes span {
	background-position:-144px 0;
}

#mainMenu .empregos span {	
	background-position:-192px 0;
}

#mainMenu .voluntardo span {
	background-position:-240px 0;
}

#mainMenu .perfil span {
	background-position:-288px 0;
}

#mainMenu .password span {
	background-position:-336px 0;
}

The extra 16px in the image might seem like a waste, but you get that down to a 8 bit (256 color) or less PNG it pretty much disappears from the file. Instead of sliding the background around on both axis (painful) we slide it up out of the anchor and increase it’s height on hover – revealing the part of the image vertically you want to show. That means we only need to say background-position once for each image to slide it on the horizontal. Means getting APO involved, but that’s not a big deal here.

So one image for all EIGHT menu items with all three states (normal, current, active/focus/hover) without having to do the rather painful:


#mainMenu .home a span {
	background-position:0 0;
}
#mainMenu .home.current a span {
	background-position:0 -48px;
}
#mainMenu .home a:active span,
#mainMenu .home a:focus span,
#mainMenu .home a:hover span {
	background-position:0 -96px;
}

For each and every menu item.

#menu a:active span,
#menu a:focus span,
#menu a:hover span {
top:-112px;
height:168px;
}

Yes that’s a very neat method and saves duplicating the background hover positions for each menu item. Don’t you have a working demo of this somewhere that the OP might find easier to follow?