Here is a very simple tutorial to design image overlays in HTML and CSS only.

Indeed, who has never wanted to quickly position a text over an image? Then change it on mouse hover or even display an alternate image?

The code provided in this article may apply to any website. Simply integrate the HTML code on a page and the CSS code into your stylesheet.

You can find different ways to do it on the internet, but I wanted to synthesize everything I found to extract a minimal and above all clean solution.

What is an image text overlay?

For me, an overlay is just a layer put on top of another. In HTML, it means that it is out of the flow, because it has to be positionned over another element, which is not possible with the default behaviour.

Note: I’m not talking here about text over a background image, which is standard in HTML, but text over an image element (the infamous img tag).

Simple text overlay with no hover

Overlay with background and text change on hover

Overlay with text and image change on hover

HTML code: original content and overlay

Content structure

The overlay-image class container encapsulates all the necessary structure:

  • original image,
  • original overlay text block,
  • image/text overlay block displayed on mouse hover.

On a page written without a page builder (HTML page or simple WordPress theme), for instance like this article, it is essential to define it in order to properly include original content and overlay within the page.

With a builder, it can be replaced by an existing container block (for example it could be the Divi “code” module, to which we simply add the overlay-image class).

The code below also includes encapsulating link tags to make images clickable, but you can remove them if not needed.

The HTML code

/* Simple overlay */
<div class="overlay-image"><a href="LINK_URL">
  <img class="image" src="IMAGE" alt="Alt text" />
  <div class="text">Image + text
    NO HOVER</div>
/* Color background and text overlay on hover */
<div class="overlay-image"><a href="LINK_URL">
  <img class="image" src="IMAGE" alt="Alt text" />
  <div class="normal">
    <div class="text">Image + text
  <div class="hover">
    <div class="text">Background + text
/* Image and text overlay on hover */
<div class="overlay-image"><a href="LINK_URL">
  <img class="image" src="ORIGINAL_IMAGE" alt="Alt text" />
  <div class="normal">
    <div class="text">Image + text
  <div class="hover">
    <img class="image" src="OVERLAY_IMAGE" alt="Alt text hover" />
    <div class="text">Image + text

CSS code: text overlay and text/image change on hover

The code below is to be included in your styles definition:

  • style.css file included in your HTML file if you work directly in HTML,
  • style.css file of your child theme if you work with WordPress,
  • or your Divi page options if the mechanism is only used at a specific location.

How to display the original or simple text overlay?

The overlay-image class allows you to set the global container when not using a page builder. In this article, I replaced the “width: 100%;” by “width: 80% margin: auto;” to add margins.

Important note: The image-overlay container MUST be “positioned” itself (here relative) in order to position its own elements.

Original image and text overlay are defined by  .overlay-image .image and  .overlay-image .text specifiers:

  • the image fills all available space,
  • the text is centered on the image using an absolute “positioning” on the container block and a X-Y translation (a CSS classic).

How to display the new overlay on hover?

The hover overlay is materialized by .overlay-image .hover, and “positioned” in absolute to occupy the entire surface of the container including original image and text (100% width and height).

When the mouse hovers, its opacity changes from 0 to 1 with a smooth transition to make it appear over the original div.

To overlay a text block only (without image), you must first hide the original text because the new image is not there to do so.

The CSS code

I tried to factorize the code to make it simple, readable, compact and easily usable. To do so, I divided it into three parts that you can pick according to your needs.

The first part is common to all three kinds of previous overlays and this is the only one needed for a simple text overlay:

/********* Simple or original overlay *******/

/* Main container */
.overlay-image {
  position: relative;
  width: 100%;

/* Original image */
.overlay-image .image {
  display: block;
  width: 100%;
  height: auto;

/* Original text overlay */
.overlay-image .text {
  color: #fff;
  font-size: 30px;
  line-height: 1.5em;
  text-shadow: 2px 2px 2px #000;
  text-align: center;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;

This part is needed by both overlays on hover:

/********* Overlay on hover *******/

/* New overlay on hover */
.overlay-image .hover {
  position: absolute;
  top: 0;
  height: 100%;
  width: 100%;
  opacity: 0;
  transition: .5s ease;

/* New overlay appearance on hover */
.overlay-image:hover .hover {
  opacity: 1;

This last part in only needed for background + text overlay on hover:

/********* Background and text only overlay on hover *******/

.overlay-image .normal {
  transition: .5s ease;
.overlay-image:hover .normal {
  opacity: 0;
.overlay-image .hover {
  background-color: rgba(0,0,0,0.5);


As you can see, overlays are not technically very difficult… It’s a shame that the mechanism is not part of all WordPress themes on the marketplace!


  • farragio

    Thank you SO MUCH for providing this tutorial. I have been searching for hours and all of the other tutorials I found made it way too complicated. Yours is straightforward and very helpful.

  • Hello,
    Can anybody help me to change font-color to black on mouseover?

    Thank you!

    • Hi Lidiya,
      You can try this:
      .overlay-image .hover .text {
      color: black;

  • Gianpaolo

    Thank you very much for this really simple and super useful code!
    I used it, with a lot of ccs modifications, in many of my Joomla sites

  • Thank you so much for this tutorial.

    How to put background color on image and on hover to image background color should be removed


    • Hi,
      You can add a background color with transparency on the “normal” overlay-image, with opacity 1, and set opacity to 0 on the “hover” overlay-image.

  • Hi! Thank you so much for this tutorial. 🙂
    I was just wondering – would this be possible to accomplish using only HTML?

    • Hi Andy,
      Do you mean without CSS? If so, the answer is no.
      But you can inline the CSS in HTML tags if you don’t want external CSS (using style=”…” instead of classes).
      Hope it can help!

  • How can I use that with Owl Carousele plugin? I need 4 divs, with inside foto+text in each slide.

    • Hi Den,
      Honestly I don't use Owl Caroussel so I can't tell you precisely.
      But if you can insert HTML in slides, you can try and use this code with the CSS in your style.css.

  • Henrique

    Excellent tutorial. Thanks for share your knowledge!

  • Thanks for this useful content. It’s always a pleasure to read your great posts filled with tips really!

  • Thank you SO MUCH! I have been looking for several days for something that lays out the whole idea so simply and clearly! This is such a helpful tutorial.

  • Diego Alvarez

    Excellent work

  • Can Taskent

    Thank you very much for this!

  • Thanks a lot Sir. This post was really helpful.

  • Tom Long

    Very nice work Yan! I wonder if there is a way to do the same text overlay with an a series of images (slide show) and when users click the image it changes to next image or when the users swipes left or right on touch screen the image changes but the texts stays the same. Thanks!

    • Hi Tom, you're welcome !
      Sure it's perfectly doable, but a bit more complex 😉
      As for me, I've never tried because I always rely on theme or plugin slider…

  • Brian Marcial Santos

    Quick question? How do you stop text bleeding out from the image say if you are going to shrink the screen to something like mobile. I am having that issue right now.

    • Well, responsiveness is always a mess when dealing with text in small areas.
      So you have to use media queries to change margins, paddings, font sizes, etc.

  • brian santos

    You don't know how much this helped. I was looking for two days for something this helpful. THANK YOU!

  • Christian

    Yan, awesome tutorial! Thanks a lot for sharing. I'm stuck with one detail – maybe you can help out.

    I'm using the second block of your HTML code and the first two blocks of your CSS code to achieve a darkened overlay (I added "background-color: rgba(0,0,0,0.5);" after "opacity: 1;" in the ".overlay-image:hover .hover" sequence) of an image with text. Works perfectly except that the darkened area is somewhat higher (it appears above the image) than the image it's supposed to cover on hover. Do you have an idea what I'm doing wrong?

    • Hi Christian,

      Maybe it's not clear enough in my post, but if you want to display a darkened overlay with text, you need to use the three CSS blocks and you don't need to add any background property. The third CSS block is used to hide the normal text because there's no new image to cover it like with image and text hover.

      Or maybe I misunderstood what you want to achieve…?

      • Christian

        Thanks for your reply, Yan. Sorry if my comment was imprecise. This should make it clearer: https://imgur.com/a/FzZtcUI
        Everything is fine on the left, but on the right I get this extra space above the image… (Now using all CSS blocks and your second HTML block.)

        • OK, so you're definitely doing right (second HTML and all CSS snippets). But I can't tell you what is happening without seeing your code.
          My guess is a conflicting CSS property somewhere in your stylesheet.

          • Christian

            Maybe this helps others:

            Asked Stack Overflow and the solution to my issue is to add "font-size: 0;" to the main container (i.e., .overlay-image).

            Nonetheless: Thanks for this tutorial, Yan. Did 99,99% of the work. 🙂

            • It's very strange because I have 100% font-size (default), and font size has nothing to do with this. If you send me the URL I can find out the real problem ; I'm pretty sure there's a CSS conflict that you can solve properly.

              • I am having a similar problem. When I hover over, the black background is oddly bigger (higher in height), so my hover image doesn’t align and is higher than the original image. Please help!

                • Hi Fay, sorry but I can’t help you without a URL. Feel free to contact me by email.

  • Thank you for this tutorial, it works like a charm! Would I be to apply this code to 3 different images in a row?

    • Hi Harry, You're welcome !
      And yes, you can apply this to any number of images, but you have to repeat the HTML code block for each one of them.
      The provided CSS doesn't need to be duplicated though, it will be applied to all of your images.

      • I see – Would I have to add any extra HTML code to make the pictures sit on the same row? I am using WordPress if that helps

        • Well, that's another (very rich) subject, but the fastest way for me is using flexbox.

          <div id="image-row">
          Image 1 block
          Image 2 block
          Image 3 block

          #image-row {
          display: flex;
          flex-direction: row;

          • When I enter the CSS the overlay misaligns from the image and there are no borders between the pictures, any idea how to fix this? apart from that it gives the desires effect! Thanks for your help

            • Sorry but I can't tell why it is misaligned without seeing your code, but I tried it and it works perfectly.
              Maybe you should learn a bit of HTML/CSS ; it would help a lot 😉

              For instance, if you want a 10px gutter between images in a row, add this CSS :
              .overlay-image:not(:last-of-type) {
              margin-right: 10px;

              CSS is very easy and very rewarding when you want to customize websites !

  • Warren Huska

    Thanks for this excellent CSS tutorial – you are right, it is a shame that most page builders skip this crucial feature in marketing – you want to describe your image in an attractive way!

    • You're welcome !
      Hope that one day ET will stop relying on 3rd party plugins…

Leave your comment