The Montoya Herald — ChristianMontoya.com
This is a pure CSS image rollover that works for image tags. Remember how you used to do them with javascript? Onmouseover() and all that jazz? You can stop now.
I was working on a redesign, and being that I'm partial to using image tags for navigation rather than crazy new-fangled image replacement techniques (pharner and etc), I was thinking of an easy way to do an image rollover effect. The solution came to me in about 2 seconds, and I'm not sure if it has been mentioned before, so I figured I would share it with you here.
The premise is simple: Enclose the image in a block level element with a defined size, and then change the positioning of the image when that block level element is hovered over, much like you would change the background positioning for background rollovers. The implementation is simple too.
Here's the setup:
<a href="#"><img src="/directory/hoverex.png" alt="redesign imminent" /></a>
And here's the image that I'm using:

The left half of the image is what I want to display, and the right half of the image is what I want to show on hover. It's 200 pixels wide and 50 pixels high, so the CSS to make the technique work is:
a {
display:block;
height:50px;
width:100px;
overflow:hidden;
}
a:hover {
display:block;
text-indent:-100px;
}
So I make the <a> tag a block level element and give it a height equal to the image and a width equal to half the image, and I apply overflow:hidden so you can't see the other half, and then in the :hover all I have to do is set the text-indent to half the image width so the image moves left and you can see the other half. That's it.
Here's an example of the technique in action:
Browser compatibility:
Problems with this technique: When the image degrades to alt text, the text will move left on hover, and probably dissappear. Not a complete usability problem, but a problem nonetheless. If you would prefer the javascript route, check out unobtrusive javascript image rollovers. Keep in mind, though, that the javascript technique requires image preloading to prevent a delay, and uses two images, whereas the CSS technique needs only 1 image to load.
Update: I'm going to dub this "MIR" (montoya image rollover) now before it takes off.
Update 2: If you are trying to get this to work inside of tables with IE6, try Eduardo Ojeda's advice:
I found a workaround for using this inside tables on IE6. For some strange reason (i’m no CSS guru, not by far) if you define a border for a:hover, the hack starts working. You just need to make the border the same color as the background. A 0px border won’t work, and ‘none’ or ‘hidden’ don’t seem to do the trick either. Also, the image moves one pixel down and right, so you need to offset that too somewhere if you don’t like the effect… This would be the code: a.rollover {display:block; height:25px; width:25px; overflow:hidden} a.rollover:hover {display:block; text-indent:-25px; border: 1px white solid}
Hope that helps.
I was in a testing mood today, so I can tell you that it works in:
IE 5.5 SP2, Mozilla 1.7.12, Opera 7.54u2, Opera 7.23, Netscape 7.01,
Netscape 6.2
while it doesn't do the trick in IE 5.01 and Opera 6.05
Hi, I'm the creator of the unobtrusive javascript image rollovers. ;-). I like your technique, but it's not "dynamic". The javascirpt method was created for my clients who don't have access to CSS of don't know CSS. So the only thing I have to do is load the script fo them (I create an html template) and the client can put his own images. He just need to follow my guidelines (naming the ID and ofcourse upload the images).
For myself I also use the real CSS rollovers
…
Greets
I see what you mean. I guess one option would be to have a PHP script that takes the dimensions of the image and makes the CSS for it (it's very simple CSS), but it's definitely not something most clients could do on their own.
I was just surprised to not have seen it before elsewhere. Everyone does rollovers with background images but I've never seen anyone try this
It also works just fine in Safari 2.0. Very nice, thanks for posting this.
Thanks for letting me know. If anyone else can test other Mac and Linux browsers, I would really appreciate it!
I'm curious - most savvy CSS developers have been using this same technique for a couple years now, albeit with background images (and a:hover { background-position:-100px; } or whatever) - what is the advantage of using an inline img as in your example above? Just curious!
Jim: There's no doubt that the most accessible image-based links are the ones that use inline images. Many CSS designers like to hide text instead and replace it with background images, but this is not good practice. They only do it because someone years ago proved it could be done and the rest of them have just followed. Thus there are a lot of CSS designs where the links dissappear when images are turned off.
Fortunately there are a few savvy developers (like myself) who look for new and more accessible ways to do things. So, here you go: a far more accessible technique that looks just as good.
The only thing is that with CSS turned off the images look a little strange with the text duplicated. Another technique would be to use an inline img and a background-image combination where you apply a background to the element and pull the img out of sight and bring it back on hover (ala splintered in the links in the bottom left).
This is a good piece of thinking outside the box.
I have seen a similar technique at alistapart article [image sprites] but even that technique uses background images with text placed -9999 px of the screen. At least this technique exploits the alt tag correctly.
@ Dylan: I know what you mean, but I think it's a toss up of which is more likely to happen. Besides, I tried the technique you mentioned and the problem with that (for me) is that it uses 2 images instead of one, which uses a little more bandwidth.
hi there,
i have seen something very similar discussed here:
http://wellstyled.com/css-nopreload-rollovers.html
thought you could be interested.
best regards
Trevor: yes, I've seen that one too… it's completely different, and very useful for text links.
Christian - Thanks for the demo! Great job! I have similar technique demo on mysite: http://www.shepherdweb.com/laboratory/css-hover-with-background-images/
Chris, you've seen my blog, right? See the city of blue and black at the top of screen, and the roll over effect?
One image makes it all happen.
Basically used the tutorial at ALA (Search on 'sprites') - took me all of an hour. Pure CSS.
Going to be adding the h1 and h5 images to it soon too - tricky stuff! (Nah, not once you get the hang of it!)
Yeah, I've seen it. Empty spaces instead of text. How accessible is that?
Works in Konqueror 3.4.3 too.
Personally wouldn't use it - looks strange when CSS is removed.
Forgot to add, that interestingly :hover images in your sites' navigation look a bit weird in Konqueror.
When the blue icon is displayed, the bottom of the white one is also visible, and vice verse. Looks like there should be more blank space between the :link and :hover images.
Rene: Thanks for the feedback. I'll edit the icons asap.
I'll agree that empty spaces is not the best idea … but I am working on that! Though I'm thinking of trying out sIFR.
sIFR is cool but I don't think you can use it on the header nav.
Your comments taken so seriously, the CSS and imagery used changed dramatically.
Mine used the same markup (IMG is the way to go), but hid the IMG with
visibility:hidden. Only advantage being you can use it inline if you need to.BTW, I love the design.
This is a really neat technique!
As far as I can tell, the only downside is not being able
to use image borders, short of placing them inside the
image. Can anyone think of a solution for this?
I don't really see this as a way forward, adding images into the html where there should be text adds more bloat to the design (and bandwidth). You should use text in the html markup for "textual information" not images, images in this case are only part of the style so should be kept in the css code.
Montoya you complain the usual css IR techniques on links leave an empty space when images are off. Well here's a solution I knocked up using the Gilder/Levin method of IR… http://www.thevisualprocess.com/dev/rollover …it could do with some refining and further testing but it works ok.
Advantages are;
1) Only one image required so faster loading cleaner design etc.
2) All styled in the css so no need to edit the html.
3) works with images off.
disadvantages are;
1) needs but thats hardly an issue.
2) IE is kinda funny and needs the usual hacks to get it working (no shock there then).
Ryan, you misunderstand some points of my technique. For one thing, it is not about adding images where there should be text. I've said a thousand times that it is only a technique and it is up to the designer to use it correctly, but what matters is that there are lots of situations where the designer has to use images for text and this technique serves to address the accessiblity issues of CSS based rollovers. It is also, by the way, less bandwidth, not more, than any other technique, including yours. Do some research on the overhead for loading files; every file usually requires about 600 bytes of overhead, so combining two images into one can save that much data, especially with files like PNG's where the compression to filesize ratio is more linear than JPGs. Doing the rollover that I provided as an example would require more bandwidth if it were done with two separate images.
And it is generally agreed upon that using images with alt attributes is the most, or one of the most, accessible ways of replacing text with images. The images degrade to plain text when there is no image support… that's hard to beat.
All that being said, your solution looks great. Do you have a blog or website where you can explain the method and share it with others? I think it would be very useful, as a lot of designers are currently using poor IR techniques that are far less accessible, and sometimes more bandwidth heavy, than mine or yours.
P.S. Ryan I just looked at your technique in IE 6 and it's definitely not working right. If it's allright with you I'm going to see if I can make it work better.
Oops the problem with IE was a missing Doctype… it should work now (not sure how I did that!)**
I agree your technique is something useful to know and I'm pleased I came across it, although I'm not sure if I'd use it due to the way I'm used to working.
I'm not sure what you mean about using two seperate images in my example, I'm using one image like you explained. I usually have one image with all my headers or buttons on and use css to shift the image to a different position rather than having lots of different headers to deal with.
I don't have a blog, although I'm totally redesigning my site at the moment so maybe I could add a small blog feature to it. In the meantime I'll work on improving this technique and get some details written up about how it works soon.
**it wont work properly in IE4/5 because I don't have them available to test anymore.
Ryan: I'll test IE 5… chances are it will only work in 5.5 but that's okay… I think we can finally call IE 4 and 5 dead browsers.
I'll just explain something though, there's a period (fullstop) in the spans. I did this because Strict Doctype doesn't like empty tags and I had to find something to stick in there. The period is removed by giving it a height of "0", a top padding of 25px (the correct height) and then setting overflow to hidden. Not ideal but hopefuly there is a better way.
Ok, I got what I expected. In IE 5.5 the technique works fine, in IE 5.0 the technique doesn't work. The images don't show at all. But this is fine because the text is still there, so I'd say you are doing good. I also tested Opera 8, which was fine.
Works in Opera 9 Mac (build3347).
Thanks TL!
Using this technique always decal the next div to the right in Opera… too bad i was loving it!
Decal? Is that a verb? I don't understand what you mean.
I'm trying it right now in IE 6.0.2900 and it's not working quite right - When I mouse-over your "redesign imminent" example the light image does not get positioned exactly right - it seems to be a pixel or two down and to the right of the greener image, so I get this slightly weird double-image effect. OK in Mozilla, tho.
I guess that's what bugs me about these little tricks and hacks - there are a zillion browsers and versions out there and everytime we try anything that's even slightly non-standard the resuklts are not reliable.
A ha ha ha ha Peter, you are funny. If you look at the original image, you will see that the pixel offset is intentional! Nice try, but my demonstration says it's compatible in IE 6 and I am not a liar
I'm trying to use your technique in a vertical nav bar. It doesn't seem to work when you put it inside of a table. The table-indent seems to be the attribute that breaks. Any idea why?
-Jake
You should put another block element inside of the table element, give that element overflow:hidden, and appy this technique to it. I think the problem is that tables always try to contain their content, so when you push something out of the space it causes problems. Applying this technique to an inner element and preventing any overflow should solve it. Let me know what happens.
I tried putting the anchor tag inside of a paragraph tag and giving the paragraph element overflow:hidden, but that didn't fix it.
Also, I tried it in Firefox 1.5.0.4, and it worked fine. It's only in IE 6 that it breaks.
I tried changing the display attribute for the anchor tag to display:inline-table, and that caused the text-indent function to begin working again, but broke the fixed size parameters. That is, it shows the entire image.
Let me know if you have any ideas.
-Jake
Jake, the anchor tag should have display:block. In total, you should have a block level element inside of a table cell, and an anchor inside of that with display:block, the exact size of the image except half the width, and overflow:hidden. All together that should work.
It doesn't work in IE 6. The text-indent function is still broken.
I've posted the page that I'm developing so that you can see for yourself. The url is: http://www.cs.mcgill.ca/~jbeard4/lepdev. Check it in IE then check it in Firefox. You'll see what I mean.
Thanks for all your help.
-Jake
Also, please feel free to email me off-list.
Thanks.
-Jake
Has anyone found a way to make this work in IE 6. All other browsers seem to be working great. Thanks
Jeff: Don't be confused. This works just fine in IE 6 unless the image is inside of a table cell. If you are not using tables for layout then you won't have any problems at all.
Montoya–thanks for the tip, it worked. Unfortunatley I am using tables for layout. Is there a work around for this, or should I start from scratch building the page with CSS completely…?
thanks4a7d3d609129a9296bf7ac0608c2097
Jeff: It really just depends on how long it will take you, and whether or not you want to commit the time to doing the layout without tables. Otherwise you could use the Javascript option for these rollovers that I mentioned in the entry.
Anyone had luck using IE 6.0? The example works in IE 6.0, but when I implement the code using class tag, ie: <a href="#" class="ImageRollover"><img></a>. I am also using .NET controls. Everything works in Firefox, as usual.
I like this code because it allows people to print without having to turn on the "Print Background Images" setting.
Kmett, as Jeff discovered, this technique does not work within table cells in IE 6. Is that the problem you are having?
That's my issue, I missed that post. I'm embedding the images on a .NET User control that is called from within a table.
- So I guess I'll need to use the background image solution.
I tested it with IE7 but doesn't seems to work.
Jessica, I'm looking at it in IE 7 this very moment and it works just fine. What seems to be the problem? What's your setup?
All I have to say is that IE7 is horrible, and to think that Microsoft is supposed to be the "leaders" of the internet. Alot of CSS stuff is getting screwed up with IE7
I can't quite get this to work in a horizontal list. I am using an all css layout and I thought I could put each element in a list and display: inline so that it would be like a horizonal nav and its not working too well.
I really like this css rollover, it seems alot easier then using the javascript alternative and I especially like it even more because I can use a reflection script, which hopefully all this attributes to smaller images. As i said in the above i am having trouble putting the list items in a horizontal array. Check it out: http://www.firebirdomain.com/roc/index2.html you can see the vertical list, any help would be great, thanks.
sorry had a bit of a css brain fart, i fixed the problem with the following:
nav li {
float: left;
}
haha
Yep, the items have to be "block" not "inline" for the rollover to work. Glad you got it to work.
thanks for the response - great work again
hello,
sorry if what I'm going to write is already covered in other messages, I'm a bit in a hurry and maybe I miss it.
I read: "why using an img instead of a background?".
well, I happened here because I have to css-ify a legacy web site made by some naive developers who just use tables and so on. I have ah horizontal menu made with graphical elements that need to hover. It seem to me there's no way to obtain this with just background and a:hover.
I am writing because, for reasons long to explain, my necessity was also to have the image to "move" vertically when hovered, instead of horizontally.
I obtained it changing margin-top instead of text-indent.
lbo moving a background image is the most common way to do rollovers these days, what exactly are you having trouble with because I find your comment confusing?
Ibo: You could have done it either way, but using actual IMG elements is much more accessible than using backgrounds. After all, links are content and it goes against usability principles to put that content in the CSS.
Christian I don't understand your logic, you are not putting content in the CSS, you are styling text by replacing it with an (background) image. This is perfectly accessible and usable when done correctly.
But your example up there is of an image being used to display text, this should really be in the html as text and then styled (using IR or whatever method is best).
However I would agree with you if the content of the image is not text.
Ryan, when you replace text with background images you remove the text from the content and put everything purely in the styling. That is the illogical way to handle content and the only reason why it sounds logical is because everyone and their mother does it. Text as images makes perfect sense if it is contextual and with the ALT attribute the IMG degrades gracefully to plain text when images are disabled. If you look into the use cases and edge cases more carefully and ignore the noise coming from the CSS community, you will discover that replacing text with background images is anything but accessible or usable.
Sorry but I disagree, and not because I'm following the crowd.
When you replace text with a background image you are not removing anything from the content. Presentationally for a user viewing a site there is no difference between a background image and a normal image. If the site coded well (i.e. semantically) there is no reason for the text not to show with images disabled.
I don't need to explain that the alt attribute describes the image content. But what you've done is take a long route back to what the content of the image really is - text. And worse of all, by using an image to present text you have stripping the content of it's original semantic meaning.
As far as I'm concerned "redesign imminent" is text and an image purely by presentational choice. It should be placed into the html as text and nothing more, only then should styled be applied using the CSS presentational layer.
Ryan, there's no need to argue this, because the use case speaks for itself. Disable images in your browser and visit a site that uses background images to replace text. That's all the proof you need.
Sorry I don't mean to argue, just discuss since i have nothing better to be doing
The problem you bring up is down to a fault in the method of applying the IR, which can easily be overcome. For me this approach makes far more sense semantically, not to forget it's also much easier to update, change and adapt to other situations.
What if you disable CSS with your method? Then you have twice the text on screen, not as bad as no text but an obvious usability issue.
Ryan: Your only problem is that you have a misconception about the IMG tag. It's a perfectally semantic contextual element when the ALT attribute is used correctly. It has nothing to do with "making sense," it's a fact. Feel free to look up the HTML specs for IMG and the way it is used by assistive devices to see what I mean.
Of course context matters but your example above is incorrect, you are using an image to present text when semantically it is just text and should be provided as such.
As I said, “redesign imminent†is text first and an image purely by presentational choice. And I am perfectly aware of how the alt attribute works thanks very much.
We'll just have to agree to disagree.
Ryan, the image above is a demo. Arguing about a demo is like arguing what color the sky should be. Actually, it's worse than that. For a real example, check out the navigation at crawdaddays.com. Feel free to argue that one.
Images for the navigation as well as decoration images in the nav list, oh dear. There is absolutely no need what so ever for any of this.
Ryan: Have you ever read anything about semantics?
Easy to use and works great, thanks for the help
I just have to say thanks. I've been trying to find a way to display a different logo when printing a page using only css. This works like a charm. Though, I'm using a div container and an image inside, it's the same thing. Thanks again!
I found a workaround for using this inside tables on IE6. For some strange reason (i'm no CSS guru, not by far) if you define a border for a:hover, the hack starts working. You just need to make the border the same color as the background. A 0px border won't work, and 'none' or 'hidden' don't seem to do the trick either. Also, the image moves one pixel down and right, so you need to offset that too somewhere if you don't like the effect… This would be the code:
a.rollover {display:block; height:25px; width:25px; overflow:hidden}
a.rollover:hover {display:block; text-indent:-25px; border: 1px white solid}
It's ugly as hell, I know. But at least it works… sort of.
It's work.
Thank you so much.
I worked with Joomla. It's OK!
Yeahhhhhhhhh!
Of course! Thanks CM, I'm going to give this a try. I've been thinking how to get a text-less, graphic only menu to provide a rollover without JS or onmouseover. This is great. I'll let you know how I get on. I'm combining it with some PHP to get the status of the links (current page, etc) with a total of three image options.
Thanks again,
Cheers,
Rufus
PS - I understand Ryan's point, but don't agree and I think it's daft making issue of your demo. You could just as easily have had a picture of a cat with a rollover of a dog so the fact that you chose to illustrate the demo with text just shows a different use. I'm going to use it for a text-less site (for photography) where the site is all about the images and everything else should be at a absolute minimum. The rollover will show simply when a very small, innocuous button is rolled-over. Good old ALT attributes for me throughout the site. I use them as a matter of course in design work (except on my own site, ironically, which is Drupal based and I need the ease of just content management) and agree that they're really important.
Another approach…
Christian and I spoke about this earlier today.
I wanted to share with the rest of this community.
http://www.wedelivery.com/du-jour/image-rollover/
Doesn't seem to work in IE 7. I tried the hacks for IE 6, but I am still shocked IE7 doesn't support this, it seems so basic. Does anyone have a clue how to fix for IE 7
Aaron: I've tested this in IE 7 and it works.
Is the image you are trying to implement inside of a table cell? See eduardo's comment above.
I tried Eduardo's technique for the rollover to work within tables in IE6 but with no success. However, entering position:absolute seems to work (Without adding to the hover state).
For example…
a.rollover { position:absolute; display:block; height:25px; width:25px; overflow:hidden}
Not sure of the repercussions though ;D
This technique is sexy! In order for it not to interferer with the default Hover state that I use, created another class made reference to it added float: left; since it was giving me issues with my table got it all working very nice!
Erick, can you please paste code of this…
I am glad this community has found my pure CSS image rollover technique useful and sexy. I'd recommend leaving tables behind when designing for non-tabular data. Also, add any id or class to the a tag, as it is the container for both images. The rear image should be position: relative, and the front image that turns to an opacity of zero on :hover should be position: absolute. The a tag should display: block and needs to be the exact size of the images used, else the hot spot will not run the parameter of your image.
Happy Holidays.
I just took a look at these rollovers, I have to say they're very clever indeed…however I tried placing them into a table to see if they still function and they don't appear to function in IE7…and some dissapear in Firefox…can they be used in tables?
Thanks a million for putting this up there…the code is so simple and clean!
Thanks in advance for your responce!
Liam
Liam, somewhere in these comments, someone mentioned how to get them to work with tables cells in IE… at least, as best as I can remember. If you can't find it, let me know.
Yeah again thanks a million for putting this up there I got it working in tables perfectly!
All the Best!
Liam
Liam - which method did you use to get this working in tables - I am having a bunch of trouble getting it working/// position:absoute is messing up the layout
Christian, any advice?? I'm sure a buch of peple use tables or have a system that puts the content into a table - please help oh clever CSS guru!
sorry I put in an old email address
Brilliant idea :)!!!!
Thank you very much …
This is indeed a very neat trick and I'm glad I don't have to resort to Javascript trickery, but is there a simple way to make this centered? margin-right/left: auto doesn't work, and neither does text-align: center. Any advice?