CSS-Plus
CSS-Plus
Play with web technologies

How to create an image caption with jQuery

May 13, 2010
Attention: This article is old and the content is outdated. I've left the article here for historical purposes.

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

.clear {
    clear: both;
}
.caption {
    display: block !important;
    position: relative !important;
}
.caption img {
    position: absolute !important;
}
.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;
}
.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

$(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
        $(".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);
            }
        );
    });
});

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/.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.

Demo