Repeating image gallery layout with CSS

nth-child magic to generate infinite CSS layout 🎩

Jez Williams
Level Up Coding

--

TLDR: Below is the final solution which is based on this A List Apart article and uses a combinations of the nth:child pseudo selectors to generate a repeating layout for any number of images. As we weren’t able to use CSS Grid due to having to still support IE.

The breakdown

A recent project that I worked on had a requirement for a gallery of images that users were able to upload. This meant the number of images where unknown. However, the layout needed to remain the same.

The repeating gallery layout

Previously I’d have used masonry libraries to dynamically generate a layout. However, they can be slow, feel a bit janky, and also required a lot of boilerplate code to run.

It turns out, you can do this with a bit of funky CSS nth-child logic. This article from A List Apart explains the concept in—a lot—more detail and really pushes the boundaries of what I thought was possible in CSS.

The final solution, might look a bit weird at first but once broken down a bit, the logic is quite straight forward.

How it works

The designed layout is a repeating pattern of 3 rows with a total of 6 images.

So to start off, all images are given a default width of 100%. This is the fallback for smaller screens and also the image on the third row.

For the first row of the layout, we need to apply 50%. As this pattern that repeats for every six images this can be done by selecting every 6th child (6n) starting at the first (+1) and the second child (+2).

This selector will go on indefinitely, selecting the first and second child for every six images.

For the second row, we need to target the third, fourth, and fifth child to give them a width of 33.33%.

This is done in the same way and uses the nth-child to select every sixth element starting from the third, fourth, and fifth child.

The last row has just one image at 100% width which it will inherit from the fallback we declared at the start.

Whola! 🙌 a nice repeating gallery layout.

Well, nearly… there are a few small enhancements which will make this layout look even better.

Odd number of images

Having an odd number of images causes the last two rows to become full width as they both get selected by the default flex-grow we defined at the start.

This is because the second to last image will be the sixth in our pattern which gets targeted by our default fall back to make it 100% width as per design. The last image in an odd set of images would be the first one in our pattern which is 50%. However the global flex-grow will cause it to be full width too.

To fix this we need to detect if there are an odd number of images. We can do that by checking to see if the last is odd :last-child:nth-child(odd) and that the child before that is even picture:nth-last-child(2):nth-child(even) and then if it applies, add a 50% width to both of those elements.

Only 3 images

When there are only 3 images, the last image is full width. Which, although, technically correct (as the first row is the first two images at 50% width) it would look better if we made put them all in one row at 33% width.

So we need to create a selector that only targets elements if it only has three children. We can do this using nth-last-of-type(3). Which, when given a number, will start counting backward from the last child. Then we can check to see if the third one from the end is also the first child by using nth-child(1) if both those selectors match, we’ll know that element is the third child. We then just need to do that for the second and first

5 images

This is just a bit of an edge case where having, but only five images will cause the last two images to be targeted by the selector we use for an odd number of images and also the selector for a row of three images (above). But we can fix this in the same way as we did with the set of only 3 images.

This rule checks that the last element is also the fifth from the start nth-last-of-type(1):nth-child(5) which we also do for the third and fourth child. Once we’ve selected all those last three images we give them all 33% to put them together on one row.

and, that’s it… 🙌

Wrapping it up

This did take me a while to get my head around at first, but I found the best way to get this to ‘click’ was just a case to trial and error.

Although this isn’t the best solution for every gallery layout, it suited our project requirements perfectly and was great to experiment with combing CSS selectors to go beyond what I thought was possible. Since the solution is pure CSS, it is highly performant as well.

I hope this helps as a reference, solution or as an interesting read ✌️

Photo by José Alejandro Cuffia on Unsplash

--

--