How To Build An Expandable Accessible Gallery — Smashing Magazine

How To Build An Expandable Accessible Gallery

About The Author

Silvestar Bistrović is a fearless web engineer, CSS developer, JAMstack enthusiast, WordPress theme specialist, author of the UI Dev Newsletter, and founder of …

More about
Silvestar ↬

Email Newsletter

Quick summary ↬

In this article, we’ll be looking at how to set up a gallery that is expandable as well as accessible with a few tips and tricks along the way. Let’s get started!

One of the use cases for using CSS Grid is to display a gallery of images, but a gallery on its own may not be that exciting. We could, for example, add a click effect to enlarge the image without affecting the grid to make it a little bit more fun. And of course, as to not exclude anybody from enjoying this feature, we should make it accessible, too.

In this article, I’ll explain how to build an accessible expandable gallery with a few tips and tricks along the way. Here’s how the final result looks like:

See the Pen [How to build accessible expandable gallery]( by Silvestar Bistrović.


First, we are going to set the HTML structure. Of course, we could always do it in various ways, but let us use a list of images wrapped in buttons.

Now, to make the gallery accessible, we need to make some adjustments:

Finally, let’s add a paragraph with helpful text on how to use the gallery, and wrap the whole code in a landmark (in this case, the main element).

For the simplicity of the demo, I decided to use images wrapped with the aria-expanded attribute. A better solution might be to add only image tags and then use JavaScript to wrap these images in a button with the aria-expanded attribute. This may be considered as progressive enhancement since the expanding effect wouldn’t work without JavaScript anyway.


To define the grid layout, we could use CSS Grid. We’ll use auto-fit so that items can fit into the available space, but restrict themselves from shrinking under a certain width. This means that we’ll see a different number of items on different viewports without writing too many media queries.

To preserve the correct aspect ratio of the image, we could use the property. To reset the button style, we could add the all: initial declaration. We should also hide the overflow of the button.

To make the image fit right into the button, we’ll use object-fit: cover declaration and set both width and height to 100%:

The expanding effect is done with the scale transformation. The transition is enabled by default, but if the user does not prefer transitions and animations, we can use the prefers-reduced-motion media query and set the transition-duration property to 0s.

More after jump! Continue reading below ↓

Meet Smashing Online Workshops on front-end & UX, with practical takeaways, live sessions, video recordings and a friendly Q&A. On design systems, CSS/JS and UX. With Carie Fisher, Stefan Baumgartner and so many others.

Before we make the element expandable, we need to prepare and calculate a few things.

First, we’ll need to get the duration of the transition by reading the CSS Custom Property --duration-on.

Next, we’ll set the data attributes for the later calculation:

The first two are pretty straightforward. We could get the values from the computed CSS style.

To find the number of columns, we should iterate through each tile and compare the top position of each element. Once the top position changes, the item is in the new row, which gets us the number of items.

Expanding Direction

To achieve the expandable effect, we should make some checks and calculations first. First, we should check if the item is in the last row and at the end of the row. If the item is in the last row, it should expand to the top. That means it should have the transform-origin property set to the bottom value.

Important: If the element should expand to one direction, its transform-origin property should be set to an “opposite” value. Note that vertical and horizontal values should be combined.

Expanding Effect

To enlarge the image without affecting the grid, we could use CSS transforms. In particular, we should use the scale transformation. I decided to make the image double in size, i.e. the factor is the ratio of the double width of the element plus grid-gap.

Keyboard Support

Users who navigate sites by using a keyboard should be able to use the gallery. Going through the list works by default when using key Tab. Emulating the click works by default by pressing the Enter key while the item is focused. To enhance the default behavior, we should add support for Esc and the arrow keys.

Once we expand the item, pressing Esc should revert it to its standard size. We could do it by checking the code of the pressed key. The same goes for arrow keys, but the action is different. When pressing arrow keys, we want to get the previous or next sibling and then emulate the click on that element.

To make the gallery element expanded, we should deactivate all other elements first. Then, if we click on the expanded element, it should revert to the standard size.

Z-index Issues

To prevent issues with z-index and stacking context, we should use the timeout to delay the transform. That is the same timeout that we calculated in the preparation phase.

Viewport Resizing

If the viewport changes the size, we need to recalculate defaults because we defined a fluid grid that allows items to fill the available space and move from row to row.

A Word About Accessibility And Credits

I had no problems building this demo except with the accessibility part. I was not sure what to do and which aria attributes to use at first. Even after figuring out which attributes to use, I could not be 100% sure it was right. So the first step was to test everything with a keyboard. That was the easy part. Then I used the VoiceOver application (since I am using a Mac) to test how it works for visually impaired persons. It sounded good enough to me.

However, even after all that testing, I was still not 100% sure. So I decided to ask for help. I am a part of one Slack community for designers and developers (BoagWorld), and I posted a question there. Fortunately, accessibility experts like Todd Libby helped me test the demo on different devices and correct the code. I also asked Manuel Matuzović for help and he helped me clean up the code.

I’m grateful to have the Internet and developer communities where we can all ask for help, get answers from professionals, and solve problems together. That is especially true with sensitive issues like accessibility. Accessibility is hard, and it does not take much to make it wrong. Less is more — at least it was in my case.

And finally, I wanted to share the greatest lesson:

Smashing Editorial
(vf, yk, il)

This content was originally published here.