Build a Horizontal Masonry Layout in Webflow

Intermediate 19:28 webflowflexboxlayoutgalleryaccessibilityno-code

Recreate a fully responsive, accessible horizontal masonry gallery in Webflow using only Flexbox — no custom code — then wire it up to the CMS.

Key takeaways

  • Building the gallery on an unordered list isn''t just semantics — it tells screen readers "list, 12 items" so the whole gallery reads as one connected set instead of a pile of loose images.
  • Flexbox does all the masonry work: give each item flex-grow and flex-shrink of 1 and the items collaborate to fill every row edge-to-edge while respecting their own aspect ratios.
  • Setting the image to width and height 100% would stretch it — object-fit: cover is the one property that keeps each photo's real aspect ratio inside the flexing item.
  • A lonely last item that stretches too wide is fixed with a dedicated spacer item (flex-shrink 0, flex-grow 10), and aria-hidden="true" keeps that empty, decorative item invisible to screen readers.
  • The item height (36vh here) is an arbitrary starting point, not a magic number — you fine-tune it per breakpoint and per image set, even switching to width-based sizing in landscape.

Video chapters

  1. 00:00 Intro
  2. 01:50 Context and notes on accessibility
  3. 03:16 Building the flexbox layout
  4. 10:41 Accessibility: the aria-hidden attribute
  5. 11:31 Responsiveness
  6. 12:52 Applying the layout to a CMS collection
  7. 17:34 A staggered animation powered by GSAP
  8. 18:43 Outro

Build a horizontal masonry layout in Webflow where photos fill out rows while keeping their own aspect ratio — fully responsive, genuinely accessible, and without a single line of custom code. It’s the horizontal counterpart to a vertical masonry grid: images sit side by side, stretch to fill each row neatly, and reflow gracefully on any screen size.

The whole thing runs on Flexbox, so it’s also one of the best hands-on ways to really feel how flex-grow and flex-shrink behave. Inspired by a classic CSS-Tricks article, the layout leans on a handful of properties that quietly collaborate to size every item for you.

We start from static images, then apply the exact same setup to a CMS collection, and finish by dropping in a GSAP staggered animation so the images slide and fade in as they scroll into view. Accessibility isn’t an afterthought here — it’s baked into the structure from the first element.

How it works

The foundation is an unordered list, and that choice is deliberate. When content lives in a list, you’re explicitly telling assistive tech that these items belong to one structured set: a screen reader announces “list, 12 items” and reads each image as part of a sequence. That, plus clear alt text on every image, is what makes the gallery accessible rather than just a wall of pictures. The list gets display: flex, wrapping turned on so children flow into multiple rows, a small gap, and its default bullets and left/bottom padding removed.

The masonry magic is one idea: let the items decide their own widths, then fill the row. Each gallery item gets a fixed-ish height (36vh on desktop is a completely arbitrary starting value — pick whatever shows your photos well) while its width is left to the image’s aspect ratio. On its own that leaves a ragged single row, so you set the item’s flex-grow and flex-shrink both to 1. Now the items cooperate: they expand to fill each row edge-to-edge and shrink to avoid horizontal overflow when a row runs out of space. Because the item is now stretching, the image inside — sized to 100% width and height — would distort, so object-fit: cover steps in to preserve each photo’s real aspect ratio.

There’s one cosmetic snag: the last item often grows to hog whatever space is left on the final row, which looks off. The fix is an extra list item acting as a spacer — a combo class with flex-shrink: 0 and flex-grow: 10 (10 is just what looked best, no science to it). But an empty list item is a red flag for accessibility: it tells a screen reader “here’s an item” when there’s nothing inside. The remedy is a one-liner — add aria-hidden="true" to that empty item so screen readers skip it as decorative.

Here are the core rules the Webflow settings map to:

.gallery-list {
  display: flex;
  flex-wrap: wrap;      /* "Wrap" under Layout */
  gap: 1.5rem;
  list-style: none;     /* No bullets */
  padding-left: 0;
  padding-bottom: 0;
}

.gallery-item {
  height: 36vh;         /* arbitrary — tune per breakpoint */
  flex: 1 1 0;          /* grow: 1, shrink: 1 */
}

.gallery-item-image {
  width: 100%;
  height: 100%;
  object-fit: cover;    /* keep the real aspect ratio */
}

/* spacer that tidies the last row */
.gallery-item.cc-last {
  flex-grow: 10;
  flex-shrink: 0;
}

Responsiveness is just fine-tuning those numbers per breakpoint: a smaller height on tablet, and in landscape it’s often cleaner to switch perspective entirely — set the item’s width to something like 28vw and its height to auto, since the viewport is wide and short. On mobile portrait, images stack, so you can revert to a height-based value and simply set the spacer item’s display to none.

How to use it

  1. Clone the project. Grab the Webflow cloneable — it ships with the full structure and styling so you can dissect every setting described above.

  2. Build the list. Inside your section content wrapper, add an unordered list with a gallery-list class, set it to display: flex, enable Wrap under Layout, add a small gap, remove the bullets under list settings, and zero out its left and bottom padding.

  3. Set up one item, then duplicate. Give the single list item a gallery-item class and an arbitrary height (start at ~36vh). Drop an image inside with a gallery-item-image class at 100% width and height. Under Flex child, set both grow and shrink to 1. Then duplicate the item to fill your gallery (12 works well) and swap in each photo.

  4. Fix the aspect ratio. Select the image and set object-fit to cover so photos keep their proportions as items stretch. Adjust the focal position only if a particular photo needs it.

  5. Tidy the last row (if needed). If the final item stretches awkwardly, add one more list item with the gallery-item class plus a combo class (e.g. cc-last), and under Flex child set shrink to 0 and grow to 10. Then add the attribute aria-hidden="true" to that empty item so screen readers ignore it.

  6. Make it responsive. Retune the item height on tablet, switch to a width-based value (e.g. 28vw) with height: auto in landscape, and on mobile portrait revert to a height value and set the spacer item’s display to none.

  7. Move it to the CMS (optional). Assign gallery-list, gallery-item, and gallery-item-image to the collection list, item, and image. The “empty” spacer is simply a collection item with no image; target it with the built-in last item state in the selector dropdown so you can style it without a combo class. Add a text field for aria-hidden (true on the empty item, false on the rest) and bind it to the item’s aria-hidden attribute. Remember a real client project also wants a text field for each image’s alt text.

  8. Add motion (optional). To make the gallery slide and fade in on scroll, reuse Francesco’s GSAP staggered-animation solution: paste its script and add its staggered-list attribute to the gallery-list element, leaving the defaults as-is. Publish and check the live page — the stagger only runs at runtime, not in the Designer.

Resources

Frequently asked questions

How do I create a horizontal masonry layout in Webflow without code?
Set the gallery list to display flex with wrapping on, give every gallery item flex-grow and flex-shrink of 1, and set the image inside to object-fit: cover. The items then fill each row edge-to-edge while keeping their aspect ratios — all from Webflow's style panel, no custom code.
Why should a photo gallery be built on a list instead of plain divs?
A list explicitly groups its items as one structured set, so a screen reader announces something like "list, 12 items" and reads each image as part of that sequence. Paired with meaningful alt text, that's what makes the gallery genuinely accessible.
How do I stop the last item in a Flexbox gallery from stretching too wide?
Add one extra list item as a spacer, give it a combo class, and set its flex-shrink to 0 and flex-grow to a high number like 10. It soaks up the leftover space on the final row so the real photos keep sensible widths.
How do I keep an empty spacer item from confusing screen readers?
Add the aria-hidden attribute with a value of true to the empty item. Screen readers then skip it entirely and treat it as decorative, so users never hear about an item that has nothing inside.
How do I apply this masonry layout to a Webflow CMS collection?
Assign the same gallery classes to the collection list, list item, and image. The empty spacer becomes a collection item with no image, and a text field bound to its aria-hidden attribute (true on the empty item, false on the rest) preserves accessibility per item.

← Back to the course

Also part of these courses