How to Code a CSS-Only Image Gallery with Animated Effects

Animation. Illustration of an image caption and color overlay that appear when hovering over an image.
Share on facebook
Share on twitter
Share on pinterest
Share on linkedin

Images are powerful! It’s unsurprising that designers not only use images but use them strategically. One of the most popular ways to display information visually is through an image gallery. Yet one of the many challenges of web design is accommodating a variety of device and screen sizes and those images need to show that same flexibility. This tutorial will code a nice, fluid and responsive CSS-only image gallery with a small slide-in animation and text overlay hover effect too. Let’s get started!

The CSS-Only Image Gallery You’ll Be Making (Animated Preview)

Animation. Illustration of image captions and color overlays that appear when hovering over an image gallery.

Why Image Galleries Are Important

Images convert better than text. For example, images improve how much people remember a piece of information (source: Brain Rules). Social media posts with images improve engagement over those with text alone, like Tweets (source: Buffer). Human beings are also attracted to images of other human beings. If an image shows a person looking somewhere, the viewer’s eyes automatically move to look there too (source: Boagworks).

Step-by-Step Tutorial for the CSS-Only Image Gallery

Begin by Updating the HTML Document

First, create the parent container for the CSS-only image gallery first. A div will act as the parent container for the whole image gallery, called collage. This groups all the collage elements all together and helps ensure individuals images stay cropped within their designated space. The .collage parent container uses two other CSS classes: columns and clearfix. The .columns class indicates the div will have a multiple-column layout. The .clearfix class indicates something inside this container uses floats. There are various forms of the clearfix hack in existence, but here I use the recommended clearfix hack from

Next create the actual columns in the HTML. The children containers within the .collage .columns div are the individual columns. The class .col-33 indicates the column is set to be 33% of the viewport’s width—so there will be a total of three columns in this row.

I recycle a code snippet on multi-columned layouts using only HTML and CSS. You can find that snippet and its explanation in my earlier tutorial, How to Code CSS-Only Columns.

Graphic. The div arrangements to make a CSS-only image gallery.

Then, add a wrapper for the image within each column. This wrapper helps “contain” the image within its box. Add the actual image as a new, uniquely named div and nest whatever caption inside that.

Now, I know what you’re thinking: why add the image as a div and not as an img? Yet, the size of the space will change per viewport size, so you can’t be pre-determine or fixe a size. Consequently, in order to make the image fill the whole space, instead add the image to the background. Otherwise, the images break out of their containers. The background styling also has another advantage: the images do not need to be the same size. The container will crop them. This is time-saving when adding multiple images to the image gallery. Basically, doing it this way allows for fluid heights! I discuss the same tactic is in detail at How to Code Fluid Heights for IFrames, Background Images, and More Using Only HTML and CSS.

Proceed to the CSS stylesheet! Begin inputting the CSS styles for the layout.

First things first in the CSS, reset the spacing in the HTML document. Eliminate any margin or padding and set the height to 100% for the html and body elements. This creates a flush, edge-to-edge finish for the image gallery. Also add the clearfix hack mentioned above.

Secondly, add the columns styles. (For quick reference, check out the tutorial How to Code CSS-Only Columns again for an interactive JSFiddle. This is a snippet I wrote awhile ago and return to often. It’s silly to re-invent columns every time I need them!) The columns rely on floats, which is where the .clearfix class added earlier in the CSS helps realign the rest of the HTML document after the columns are done.

The .columns element acts as a row for each of the columns. If there are multiple rows but column width stays the same, each individual column element—.col-25.col-33, and so on—can be added one right after the other. If however there are multiple rows but column width does change, then the .columns element must be closed and re-opened at the point column width changes.

The individual columns are divided by eighths, quarters, halves, and a whole. Column names cite the percentage of total viewport width they occupy.

Graphic. Illustration of how to name and nest various HTML divs to create CSS-only columns.

Next, I briefly style text for the HTML document overall and finally proceed to the collage styles.

Style the Text Overlay for the Image Gallery.

In the collage styles, I again reset any margins and padding to zero just in case any web browsers have added any for the containing elements so far. Then I style the .photo-wrapper. The display is set to relative so I position the .photo-wrapper’s child elements absolutely. (This combination allows the color and text overlays to exist beside the image but “off-screen” for the moment.)

Hide overflow to prevent an image or overlay breaking out of its container.

Because I want to add an animated zoom effect when the user hovers over an image in the gallery, I add my transition timing here as well.

Finally, I finish the .photo-wrapper styles with something devised for a fluid height. That’s right! Fluid height. Adjust the padding here to the desired aspect ratio. Here’s a quick recap from the fluid heights tutorial again.

For this text overlay, I want two parts. The first part describes the image, and the second part provides copyright and credit information. Each part received its own span in the HTML. Target each in the CSS using the :nth-child() pseudo-selector.

Styling .photo-wrapper is done, so next we style the actual images at last. In the CSS, the individual images are simply targeted with specificity, as  .collage .photo-wrapper div, because each image has a unique ID that would be tedious to list all those IDs. Set width and height to 100% to ensure the image completely fills its space. Designate a transition time for the zoom animation effect that runs on hover. Set backface-visiblity to hidden.

(Backface-visibility determines whether the backside of an element will show. For example, it’s useful to animate a card flip when it’s visible. However, this CSS-only image gallery design doesn’t need back-face visibility.)

Finally, be sure to set the position to absolute. This assists with the fluid heights.

Add the CSS-Only Animations to the Image Gallery.

To animate the zoom-in effect on the image on hover, position each edge to zero to ensure the image fills the container then apply a transform: scale() of greater than one to indicate 100+% of the original image size.

Likewise, apply any transformations to the image text spans. Since the image element is bigger for the zoom effect above, size the image captions smaller, back to their “original” size. Use transform: scale() and apply the inverse of the zoom scaling.

For the zoom on the image above, I scaled the element to 1.4 or 140%; now to return to the image caption to its original size so it’ll once again fit the container, I scale it to the inverse of 1.4. In fraction form, the decimal 1.4 becomes 14/10 or more simply 7/5. The inverse can be calculated by (1/1) / (7/5), which is also equal to (1/1) • (5/7), which equals 5/7, which again back in decimal form is 0.7142857… I rounded up from .71 to transform: scale(.72) since the overlay wasn’t quite flush with the image edges.

I add a second animation effect to the color and text overlay with a translateX(139%) to slide it over the image.

Finally, once all the containers and styles have been defined, I define the images. Remember all those unique IDs for the .collage .photo-wrapper divs? Now add background images to each. Shorthand is fine, and make sure background-size is set to cover to make it fill the whole space.

Test and validate your code for any bugs. Ta da! Now you have a full-size, fluid and responsive image gallery complete with zoom and sliding animations plus color and text overlays!

Final CSS-Only Image Gallery: