How to create an image caption with jQuery

I’ve been meaning to create an image caption for a while now and instead of putting it off I just decided to do it. This image caption is not a plugin – It merely allows you to understand how a jQuery image caption would be created. I will eventually turn it into a plugin with useful options, etc. But for now, this will just have to do.

Let’s get started:

The HTML

The markup is very simple:

<p class="caption">
    <img src="images/image1.jpg" alt ="" />
    <span>Rainbow and Tree</span>
</p>

<p class="caption">
    <img src="images/image4.jpg" alt ="" />
    <span><big>Pellentesque habitant</big>morbi tristique senectus et netus.</span>
</p>

As you can see, all that is needed is a paragraph tag with a class of "caption" that contains an image and a span tag. The span tag would be the caption information.
If you would like a heading within the caption, just enclose it within a <big> tag.

The CSS

div.clear { 
  clear: both; 
}
p.caption { 
  display: block !important; 
  position: relative !important;
}
p.caption img { 
  position: absolute !important
}
p.caption span { 
  background: #000; 
  background: rgba(0,0,0,0.8); 
  color: white !important; 
  display: none; 
  padding: 5px 10px !important; 
  text-align: center; 
  position: absolute !important;
  bottom: 0 !important; 
  left: 0 !important; 
}
p.caption span big {
  font-weight: bold; 
}

I've thrown quite a few !important's around to make sure other CSS selectors don't interfere with it. There isn't really anything interesting going on within the CSS. The span is set to display none because we only want it to display once we have hovered over the image. So for now, it is display: none.

The jQuery Javascript

$(window).load(function(){ 

  // For each instance of p.caption
  $("p.caption").each(function(){
    $(this)
      // Add the following CSS properties and values
      .css({
         // Height equal to the height of the image
        "height" : $(this).children("img").height() + "px",
        // Width equal to the width of the image
        "width" : $(this).children("img").width() + "px"
      })
      // Select the child "span" of this p.caption
      // Add the following CSS properties and values
      .children("span").css(

        // Width equal to p.caption
        // But subtract 20px to callibrate for the padding
        "width", $(this).width() - 20 + "px")

      // find the <big> tag if it exists
      // And then add the following div to break the line
      .find("big").after('<div class="clear"></div>');
    
      // When you hover over p.caption
      $("p.caption").hover(function(){

        // Fade in the child "span"
        $(this).children("span").stop().fadeTo(400, 1);
        }, function(){
        // Once you mouse off, fade it out
        $(this).children("span").stop().delay(600).fadeOut(400);
      });
  // End $(this)   
  });

});

It might look quite confusing but it's all very simple actually. What I've had to do is break up the code so that it is readable, otherwise it would all be on one line. Everything is done on a single $(this) statement.

The p.caption element's width and height are set to the same width and height as the image. That way there is a - {position: relative;} - wrapper and we can make the span tag act as a caption by sticking to the bottom of the image/wrapper.

Note: On the span tag - padding is definitely needed other wise the text sticks right up against the top and sides. This is the reason width: 100% could not be applied to it within the CSS, otherwise the span would start moving outside of the wrapper. Padding has been used on the span, but this is only because the total span-padding-width has been subtracted from the span's total width within the javascript.

//Set the span's width to the width of the image/p.caption, but subtract 20 - This 20 refers to the 10px padding on either side.
"width", $(this).width() - 20 + "px")

Finally

So far, this image caption works with IE 7+, Opera 10, Webkit browsers and Firefox.
I hope you found this useful. As I mentioned before, I am going to turn this into a cool jQuery plugin for you and I to use, so if you have any cool ideas, or if you notice any problems, just drop off a comment. Thanks.

What say you?

  1. Tim Peters says:

    Hi Jamy,

    First of all, thanks for your useful information on your website.
    I was reading your tutorial ‘How to create an image caption with jQuery’.

    At the moment I try to make a website with a grid of thumbnails with image captions ( I’ve tried yours and it works well). But I want to make this, in combination with Jquery Vgrid: http://jquerystyle.com/2010/03/25/vgrid
    http://blog.xlune.com/2009/09/vgrid/demo005.html

    I really don’t know where to start.
    Do you have an idea to make a good combination with photos with the image captions + the Jquery Vgrid system?

    Thanks in advance,
    Tim

  2. Hello,

    I think there is a error in the js….

    Instead of:

    // Width equal to p.caption
    // But subtract 20px to callibrate for the padding
    “width”, $(this).width() – 20 + “px”)

    it should be:

    // Width equal to p.caption
    // But subtract 20px to callibrate for the padding
    “width”, $(this).children(“img”).width() – 20 + “px”)

    1. Hey, yeah the script does need to be changed there, but it should change to:

      $(this).parent(),width() – 20 + “px”)

      I should actually update the entire script, I would create it in a slightly different way if I had to do it now.

  3. tac says:

    This is great.
    Thank you sooooo much!
    from japan.

  4. overkill says:

    Thanks for this. It was very basic and easy to understand (exactly what I was looking for). But I’m doing weird things and $(this).children(“img”).height() seems to always return 0.

    I’m trying to setup a thumbnail gallery using div.caption (float: left: width: 150px;) instead of p.caption. And the images are shrunk via css with { max-width: 100%; }.

    The img width calculates and sets the div.caption witdh, but the img height always returns 0. If I replace $(this).children(“img”).height() with a fixed number, div.caption height is set (and works). But I’d prefer to match the actual image height.

    Thanks

    1. Jamy Golden says:

      Do you have an example of this problem I could have a look at?

    2. overkill says:

      (Hope I’m not double posting, but I didn’t see my comment show up)

      I put up two samples here. http://db.tt/wrTk5rIC More details are in the link.

      Thanks so much for looking at this.

  5. Vinod says:

    I found your code help ful to me and did this in easy way with out plugin,

    $('#portfolio li img').each(function() {
    		$("").text($(this).attr("title")).insertAfter($(this));	});	
    	$('#portfolio li').hover(function(){
    		$(this).children('h4').slideDown();
    	},function(){
    		$(this).children('h4').slideUp();
    	});

    hope this helps some one who are looking for simple code for beginners like me

  6. Hi there,

    I’m having troubles with this. I can’t seem to disable the height of the image so it is responsive with the rest of my design. See here: http://alistairwilliamsdesign.com/test/grid.htm the top 3 images have the Image caption applied and the bottom 6 don’t. When you scale the browser the top 3 don’t scale correctly. Could you help me out on this please? cheers Al

    1. Jamy Golden says:

      The image caption contains a set height – probably added by javascript somehow. Once you get rid of that it should all work as expected.

  7. Jackitshot says:

    hello, i want to add <a href="myurl"> into The HTML code.
    For example,

    <a href="myurl">   (add my link)
    </a>
    Rainbow and Tree

    but The CSS doesn’t help to display corrent span size on image, how could I to modify The CSS? thanks!

    1. Jamy Golden says:

      Hi. This is a very old article and I should update it. This is a much more simple (and better) way of doing this: http://jsfiddle.net/WEWvs/2/

      It could even be done without javascript at all: http://jsfiddle.net/WEWvs/3/

    2. Jackitshot says:

      Cool, that’s good solution
      I am back from weekend vacation and test your two demos, they are passed in my website successfully. Thanks, I love you so much! :) (Chinese people are shy usually, but I am not! )

  8. Abhishek sen says:

    Thanks for creating such a helpful article. looking forward for more.