CSS

CSS Grid: 2-Row Auto-Column Gallery (2025 Tutorial)

Tired of complex gallery layouts? Learn how to create a stunning, responsive 2-row, auto-column gallery with just a few lines of modern CSS Grid in 2025.

E

Elena Petrova

A front-end developer and CSS enthusiast passionate about creating elegant, responsive layouts.

6 min read17 views

CSS Grid: 2-Row Auto-Column Gallery (2025 Tutorial)

Let's be honest. For years, creating a truly elegant, responsive image gallery felt like a dark art. We wrestled with floats, painstakingly cleared them, and battled bizarre whitespace issues with inline-block. Then came Flexbox, a revolutionary step forward, but it still sometimes felt like we were trying to fit a square peg in a round hole for complex, two-dimensional grids.

Well, welcome to 2025, where CSS Grid isn't just a shiny new toy anymore—it's the battle-tested, undisputed champion of 2D layouts. Today, we're going to build something that would have been a headache just a few years ago, but is now wonderfully simple: a gallery that always has exactly two rows and automatically adds columns as needed.

No fragile hacks. No convoluted media queries for the core logic. Just pure, clean, modern CSS. Let's dive in.

From Float Frustration to Grid Glory

Before we build, let's appreciate the journey. Why is Grid the perfect tool for this specific job?

  • Floats: The original method. It worked, but it was never designed for layout. We had to "clear" floats to prevent parent containers from collapsing, and getting items of different heights to align properly was a nightmare.
  • Flexbox: A massive improvement, Flexbox excels at distributing items along a single axis (a row OR a column). While you can make it wrap, forcing a strict two-row layout where items flow vertically first is unnatural for its one-dimensional model. You can often get close, but it's not what Flexbox was born to do.
  • CSS Grid: This is where we strike gold. Grid was explicitly designed for two-dimensional layout—controlling both rows and columns simultaneously. It gives us the power to define a strict row structure while letting the columns flow automatically, which is the exact recipe for our gallery.

The HTML Foundation: Keep It Simple

Great CSS starts with clean, semantic HTML. For our gallery, we don't need anything fancy. A simple container element with our images inside is all it takes. This could be a <div>, a <section>, or a <figure>—whatever makes the most sense in your document structure.

<div class="gallery">
  <img src="path/to/your/image-1.jpg" alt="A vibrant abstract painting">
  <img src="path/to/your/image-2.jpg" alt="A serene mountain landscape">
  <img src="path/to/your/image-3.jpg" alt="A bustling city street at night">
  <img src="path/to/your/image-4.jpg" alt="A close-up of a dew-covered leaf">
  <img src="path/to/your/image-5.jpg" alt="A minimalist architectural detail">
  <img src="path/to/your/image-6.jpg" alt="A playful golden retriever">
  <!-- Add as many images as you like! -->
</div>

That's it. No wrapper divs for rows, no special classes on the items. The magic will happen entirely in our CSS.

The Core CSS: Just Three Lines of Magic

This is where the fun begins. We're going to target our .gallery container and apply a few Grid properties that do all the heavy lifting.

.gallery {
  display: grid;
  grid-template-rows: repeat(2, 1fr);
  grid-auto-flow: column;
}

Let's break down what's happening here, because understanding these three lines is key:

1. display: grid;

This is our entry ticket. It turns the .gallery element into a grid container and makes all its direct children (our <img> tags) grid items. Without this, none of the other grid properties would work.

Advertisement

2. grid-template-rows: repeat(2, 1fr);

This is the first part of our secret sauce. We are explicitly defining the track for our rows. Here's the breakdown:

  • grid-template-rows: The property for defining the rows of our grid.
  • repeat(2, ...): A handy function that says, "I want to create 2 of the following track definition."
  • 1fr: The "fractional unit." This tells the grid to give each of our two rows an equal share of the available vertical space in the container. So, each row will be 50% of the container's height.

We've now locked in our two-row structure. But if you check your browser, it might not look right yet. By default, Grid fills rows first. That's where the final piece of the puzzle comes in.

3. grid-auto-flow: column;

This is the hero property. By default, grid-auto-flow is set to row, meaning Grid places items along the row axis, and when it runs out of space, it wraps to a new row. By changing it to column, we flip that logic on its head.

Now, Grid will place items along the column axis first. It will place the first image in row 1, the second image in row 2, and then—since it has filled the defined rows—it will automatically create a new column and place the third image in row 1 of that new column, and so on.

Imagine a newspaper layout. Instead of writing a line left-to-right and then starting a new line below, you're filling a column from top-to-bottom and then starting the next column over. That's exactly what grid-auto-flow: column does for our layout.

Polishing the Layout for a Professional Look

Our core logic is working, but the gallery probably looks a bit raw. The images might be squished, touching each other, and distorting to fit their cells. Let's add some essential finishing touches.

Adding Space with `gap`

Forget setting margins on individual items. Grid has a beautiful `gap` property that handles all the spacing for you.

.gallery {
  /* ... other properties */
  gap: 1rem; /* or 16px, 1.5vw, etc. */
}

This single line adds a 1rem gutter between all our rows and columns. It's clean, simple, and far easier to manage than old-school margin hacks.

Responsive Columns with `grid-auto-columns`

Right now, our columns are created automatically, but their width is determined by the content. We can gain more control with the grid-auto-columns property. This lets us define the size for any columns that are implicitly created by grid-auto-flow.

.gallery {
  /* ... other properties */
  grid-auto-columns: minmax(250px, 1fr);
}

The minmax() function is another superpower. This rule tells the browser: "Make each auto-generated column at least 250px wide, but if there's extra space, let them grow to fill it equally (1fr)." This gives us responsive columns without a single media query!

Preventing Image Distortion with `object-fit`

Finally, our images might have different aspect ratios. To ensure they fill their grid cell without getting stretched or squashed, we'll apply some styles directly to the `img` tags.

.gallery > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

width: 100% and height: 100% make the image element fill its assigned grid cell. The magic is object-fit: cover;, which tells the image to cover the entire area, cropping itself either horizontally or vertically as needed to avoid distortion, just like background-size: cover.

The Final Code

Putting it all together, our complete, beautiful, and robust gallery code is remarkably concise.

/* The Gallery Container */
.gallery {
  display: grid;
  gap: 1rem;
  
  /* The Magic Sauce */
  grid-template-rows: repeat(2, 250px); /* Using a fixed height for rows */
  grid-auto-flow: column;
  grid-auto-columns: minmax(200px, 1fr);
  
  /* Optional: for horizontal scrolling */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

/* The Gallery Items */
.gallery > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  scroll-snap-align: start;
}

Note: In this final version, I've updated grid-template-rows to a fixed height (e.g., 250px) and added `overflow-x: auto` for a common use-case: a horizontally scrolling gallery. The `scroll-snap` properties are a nice UX bonus, making the scroll behavior feel crisp. If you prefer a wrapping grid, you'd simply omit the `overflow` and `scroll-snap` properties and ensure your gallery container has room to grow.

Wrapping It Up

And there you have it. A perfectly structured, responsive, two-row gallery with an automatic number of columns, all powered by a few declarative lines of CSS Grid. This is the power of modern CSS: solving complex problems with simple, elegant, and readable code.

The next time you need a grid-like structure, especially one with a fixed number of rows or columns, reach for these properties. Experiment with them! Change grid-auto-flow back to row and define grid-template-columns instead. The concepts are transferable and will make you a more effective and efficient front-end developer. Now go build something amazing.

Tags

You May Also Like