I don't mind living in a man's world as long as I can be a woman in it. – Marilyn Monroe

Place text over images on hover without JavaScript

Thanks to CSS3 and better and better browser support for it, we can accomplish things now with CSS that previously required fancy JavaScript work. In this tutorial, I’ll walk you through fading in text over an image on hover.

Tutorial Updated

I updated this tutorial to show you how to take advantage of even more CSS3 properties. The update is available here.

If you move your mouse over those images, you’ll see some text fade in that tells you where each photo was taken. When you move your mouse away, the text fades away.

Nice, right? And look ma, no JavaScript. So let’s get started.

Step 1: HTML Markup

To keep things neat and tidy, I’m going to put my images in a list. Each list item will contain an image and a couple of nested <span>‘s to hold the text that should appear when my site visitors hover over the images. Then I’ll wrap all of that in a link.

I’d just repeat that list item and everything inside of it for each image that I wanted to include.

Step 2: Style the Images

Now that we’ve got the markup out of the way, let’s jump into the CSS. First up, we want to get rid of the bullets and line our images up across the page.

I’m setting the width and height of each list item to the width and height of my individual images, and then lining up the list items by setting them to display: inline-block.

Step 3: Place the text over the images

Now we’ll take that text description for each image and place it on top of the image.

There’s a few handy techniques here I’d like to draw attention to. First up, that rgba color I’m using for the background of the outer span. That will allow me to make my background color partially transparent by specifying an alpha value in addition to values for red, green, and blue. In this case I’m setting the background color to 50% transparent black.

Next up, I’ve set that inner <span> to display: table-cell. That lets me use the vertical-align attribute to place my text right in the middle of the image. If you’ve worked with CSS for any length of time, then you know that vertically-aligning anything to be in the middle of a container is pretty darn tough. This is a pretty straightforward solution that works without a lot of weird workarounds. It will work pretty nicely cross-browser, but be aware that it will not work in IE8 or any earlier version of IE.

Step 4: Show the text on hover

Now I only want to show that text when the mouse is over the image. We just have to make a couple of quick additions to the CSS file.

The change I made there was to set the opacity of the outer <span> to 0. That will make it completely transparent. Then when the mouse is hovered over the list item, I’ll change the opacity of the <span> to 1, making it fully opaque.

Step 5: Add the animation

It’s looking good so far, but we’re missing the animation. Well, you’ll be glad to know that’s it’s very simple to add that in. We just have to use the new CSS3 transition property.

Unfortunately, just now, we still have to include several lines that include the browser prefixes for the transition property, but in time that will shrink to just one line. We just specify which property we want to animate, opacity in this case, and then how long the animation should take.

There are some additional options we have, for example adding easing to the animation. If you’re interested in digging into CSS transitions a bit more, I recommend taking a look at Chris Coyier’s CSS Tricks article that explains transitions in detail.

This is also a great example of progressive enhancement – site visitors with browsers that have support for CSS3 will see the nice animation. But those who have older browsers that don’t support CSS3 transitions yet will still be able to see the plain hover effect, just as it appeared after Step 4, before we added the transition property.

And that wraps it up. That wasn’t so hard, was it? Have some fun experimenting with adding different CSS transitions – you can accomplish some really nice effects – like animating the color changes on menu items and links. Post a link here to what you’ve built so we can all see and learn from one another.

You’d just have to include it inside the container that’s holding the text and probably give a class to the div or paragraph that holds the text so that you could select that text to style it separately.

I know this is an older tutorial – but, I have images in a table and trying to figure out how to get this to work with images in a table – can you please advise? Not sure what I need to change inside the table cell to make this work. Thank you for your time.

You can either float your images or switch their display to inline-block. If you look carefully at the CSS for step 2, you’ll see that I’ve used display: inline-block to display my images side-by-side.

Thanks for your reply. This question is purely technical not related to user experience. Since hover is replaced by touch in mobile, was wondering how to show the same effect (Showing some text when user selects/touch an image ). Both hover and click event will be triggered with a single touch.

Since there is no such thing as hover on a touch device, you can’t replicate hover functionality. Most touch devices will trigger hover events on touch, but in this case, the images are also links, so as you’ve observed, you see the text, but the browser also follows the link. It would be possible to add some JavaScript for touch devices that would show the text on the first tap, and then follow the link on the second tap, but I’m not sure how valuable that would be – it might end up being more annoying than anything.

It works great for a single image! But how to do it for a group of images? I’ve got a group of images which must contain the same class for some reasons. Then the code didn’t work, I tried to give each a different ID and replace the above code with the ID, but it still didn’t work.

This code example is working on a group of images already – I have this working with three images in this example, but it would work just the same with one or twenty or one hundred images. I haven’t used any ID’s – I’ve used all classes.

Hi Julie! There isn’t anything about position: relative that should prevent border-radius from working as it normally would. Here’s an example showing the same demo above, but with rounded corners: http://codepen.io/anon/pen/BxLFK/

I applied your code and it works fine. However, when i expand the width of the text-content bigger than than the image and i could not make the table stay on top of every images although I add the visibility: visible on the hover section. Please let me know what i did wrong.

Awesome Tutorial, thanks alot Natalie!
I have a further question, how do i get this effect working on an image slideshow loop? So, there are moving images from right to left via keyframe animation and i want your effect to show up when i’m hovering over a single image.

What version of IE did you test? Not all versions of IE have support for CSS3 animations, and some older versions also do not support the :hover pseudoclass on elements other than links. You’d have to do some workarounds to get this working in those versions of IE.

Thanks, looks great on my website sidebar using multiple vertical images. (Code worked fine once I removed the closing /ul tags between images, until the last one). Not working at all with Internet Explorer 8.0 though. At least not using IE default settings. The hover text is constant, does not appear or disappear with onmouseover/out. IE Compatibility view only makes things worse. But then, does any web page or content work properly when using IE? Lol not very often.

Hello Natalie and thanks for the great tutorial/s.
I have just started learning a bit of web coding and I have had a go at your text over images code. At this stage I am just experimenting with one image on an otherwise blank “test page” that I use for development. I have posted the code at http://jsfiddle.net/XvCbm/embedded/result/ but I cannot work out why the image has a blue line at the bottom of it. If you have the time and inclination might you be able to tell me why the code is rendering this line.
Thanks again Pedro.

The blue line is happening because of a conflict between the styles that you’ve set for your navigation and the image rollover. You might want to apply those navigation styles only to your navigation rather than to all unordered lists and list items on the page.

Thank you so much for this awesome tutorial! I’ve been searching for a “text over image” hover effect, which would work in Contenido without much trouble, for several days. This one just works excellent! Thank you, thank you, thank you! 😀

Thanks again Natalie. As a result of your excellent tutelege I separated the style declarations for my navigation and image rollover css and resolved the problem. I am now just trying to precisely position several images on a page but I am working on it. Here is how I resolved the style conflict http://jsfiddle.net/5VQb9/embedded/result/ and thanks again Pedro.

Awesome tutorial. Quick question, how would I make the hover responsive? The image is now, responsive but the hover expands the full height? I tried over-flow:hidden,max-width/height:100%, no luck? Any tips? Thanks 🙂

Hi Julia! If you set the width of the image container to a percentage rather than a fixed value and left out the height declaration, you could then use top, left, bottom, and right values to absolutely position the text over it, making it automatically fill that same space.

Hi! I have the same problem! Can you help us ? 🙂 I have four images inline-block, width of each is 25% so they respond to change window size. I have no idea how to make the text always in center of image.

So how would I incorporate that code with the text on hover code?
Likewise, further down that page http://imgur.com/q4ZthV9 there are another five images of various sizes and positions and I would like to have your text on hover code work on them as well. Thank you so much for taking the time to help me Natalie, I do appreciate it and I hope you have a happy and safe Easter. Pedro.

I am still not sure what use this is because I think that once I try to incorporate it into any responsive type code it will break because of the positioning I have applied to the image and hover text, but as an academic exercise I found it helpful to aiding my learning . Thanks Natalie and I hope you do not mind me posting it here just in case anyone else might find it useful http://jsfiddle.net/NMnED/embedded/result/

Thank you for this coding! In IE8 the text simply appears over the images. Is there a simple way to add a conditional line to turn off the text when a browser does not support the script? It doesn’t show the text on my android browser which is great because it pops up after you click, confirming your selection.

Great article thanks. I’ve been trying to do this for ages and you’re the only one that’s explained it clearly enough for me to follow.

Can you please help me further though, my home page consists of 9 images that are displayed in a 3×3 grid which I created using tables in WordPress. Each cell has the HTML section of your tutorial in it for each image.

If you take a look at http://www.paulfraserconsulting.com you’ll see, however the hover box is not aligned to the image and I can’t work out how to sort this, do you have any ideas please ? I think it’s got something to do with the bullet point pushing the image down. I would really appreciated your help.

This saved me so much work and stress and it works great, except on iOS7. Any chance you could take a look at my code at http://instapeer.org/beta? The hover works flawlessly on all other platforms and browsers. Thank you!

I don’t have an url to click on. But I want to show the visitors only the text and that is working. But on a mobile when you have six pictures, when you click for example on the third, fourth, fifth and sixth image the text is still over the picture but the you see the top of the pages and you have to scroll to that image. How can I change this that the image where you click on is still in the ‘picture’ 😉

This was very helpful and clear, Thank You! My question: I’m not much of a coder, I guess you could call me a “google it” coder, which is what brought me here. Is there a way to set the css so that the image sizes can change throughout my website and the dimensions of the image and the overlay are determined by the html at each image? With my little understanding of this stuff, all I would know to do is create a new css class for every different size image on my website, but that seems like it’s not the only or best way. Thanks again!

Great tutorial. I am trying to add this to my project using foundation 5 and having some issues. I tried with just the one class for the images (‘img-list’) but the hover content would show up only on the first image on mobile (the first and second showed up on the first) so I changed some things up. Here is my html:

how would this work with responsive images and images of varying sizes? I’m trying to center a hover image/icon vertically, but it’s not working. Do you know to fix this? http://jsfiddle.net/sas7yqo5/1/

Thank you for your awesome tutorial! It did exactly what I was looking for. I love CSS3 and would rather find a Css3 solution before using JavaScript.
On my website http://www.lasherworks.ca, I created menu bars using only images on . Two of three have descriptions in the form of unordered lists. I wanted a display that would only appear in a hover state and would look a lot nicer than a title element for my third menu bar images. I added your coding to my menu bar that is already activated by JavaScript to “sproing” or expand and enlarge in a hover state (another tutorial). With a little tweaking I managed to bring the two together and complete what I had envisioned.
I have added your tutorial to my link page along with the rest of the resources I used that went into building my website. Thanks again!
Mike Lasher

I’m having a problem though. Whilst it displays well in Firefox, Chrome, IE10 and IE9, in IE8 the formatting is all over the place. Just wondering if there is something I could do, as your code looks so beautiful and is bringing the university site to life! Thanks!

Many thanks for the brilliant tutorial. I am struggling with the opposite problem to some previous comments; I’d like to arrange my photos vertically down the RHS of my webpage. Is it as simple as deleting the display: inline-block; line of code?

Thank you for your tutorial. I have gotten it to work but I am trying to work out a few kinks.

I am using 75px x 75px images. When I hover the caption does not fit the image and is cut off. I thought it would be a simple fix by adjusting the font size. But when the font size is adjusted it actually shrinks the entire hover content. So my text is smaller but the black background that fades in with it is also smaller.

Do you have any suggestions on how to make the text smaller in the caption upon a hover?

Hi Natalie, thanks for the tutorial. In using opacity: 0 to hide the rollover text at first, you are in effect hiding text on the page. I bring this up because though unintentional, hiding text is against Google’s webmaster guidelines. If being found in search is something to consider, keep this in mind.

Thank you for the great article! I’m trying to have the text so it’s not hidden at the start – perhaps it could be a different colour (Might help with the google ‘issue’ as above?). I have played around with opacity settings to no effect. Any pointers?

First, thank you for the great and easy to read tutorial. My problem though, is this:
my images have different heights (but the same width of 475px). So I was wondering if there is any way to tweak the code to make the same hover effect, but for the different heights (instead of the 150px you used for your images)?

For folks w/ using dropping this into a responsive framework like Bootstrap or Foundation (Ysabel, maybe in your case also) it seems that styling the span.text-content to have a width of 100% and a height set in rem works…

Hello,
Thanks for the great tutorial! I am just beginning to learn coding, and this might be a simple question, but I need the images to be 300px instead of 150 px, however when I change them in this section
ul.img-list li {
display: inline-block;
height: 150px;
margin: 0 1em 1em 0;
position: relative;
width: 150px;
}
it changes the hovertext position but the image size remains 150 px. any suggestions?

Hi Natalie,
This is just what I’ve been looking for.
For some reason, however, my overlay is slightly above the images.
I have the position:relative exactly as you do. I have the image width and height in both CSS and html set the same.
Thoughts?

I just have a question regarding the images. Instead of squares I used a portrait format. my images are 300 by 424, but they look so pixelated. I have them in high res, and the process is simple. you just make a 300 by 424 canvas drop your image and scale it down. AT 100% it looks great on psd but somehow when I put them in the grid it totally looses the sharpness. Any idea why?

This was great! Very straightforward and easy to understand. Added a nice tough to my final school project. Have you done a tutorial on the clearbox widget or lightbox? Do you have youtube tutorials as well? You could give some of these guys on youtube a run for their money.