The Flexible Thumbnail Grid Problem
CSS layout has long been a source of frustration for developers, even those comfortable with more mathematical CSS features like transforms. A particularly tricky problem: creating a grid of fixed-size thumbnails that remains centered relative to surrounding text while the last row's items align left — all with a grid width that depends on the viewport.
Why Traditional Techniques Fail
Floats were an early dead end. While they handle left alignment of the last row, they offer no mechanism for centering the grid as a whole.
inline-block seemed more promising. But setting text-align: center on the container centers every row — there was no obvious way to keep the final row left-aligned.
A CSS property called text-align-last appeared to offer a solution. Setting text-align-last: left on the grid didn't work. Combining text-align: justified with text-align-last: left only produced acceptable results when the last row had exactly one item and the column gaps weren't too wide.
Flexbox offered hacky workarounds. One approach added an ::after pseudo-element to the grid with flex: 1 — the same flex: 1 applied to each thumbnail. This creates a layout that looks acceptable only when the last row is missing exactly one item. If the final row is missing more items or is completely full, the layout breaks.
A variation of this idea involved placing empty CSS Grid seemed like the logical answer, but common examples all relied on predefined column counts — not suitable for a grid where the number of columns depends on the viewport width. One creative workaround: generate a series of media queries that modify a CSS variable ( While functional, this approach is far from elegant: one media query per possible column count, and it breaks down when the grid width doesn't equal the viewport width but rather depends on sibling element widths. A better solution emerged during a frustrating session with CSS Grid. While investigating why the The Making the thumbnail width responsive requires an This ensures images never exceed 100% of the container but never shrink below 8em. Note the One limitation of this technique: it only looks clean when all images share the same aspect ratio. For images with different aspect ratios, the grid becomes inconsistent: The flexibility extends gracefully if you want certain elements to span multiple columns. Since the column count is viewport-dependent, you can't hardcode a Making the first item a full-width banner with a larger The keywords The choice between them may ultimately come down to preference. With The Media Query Solution
--n) representing the column count used in grid-template-columns./* Simplified illustration of the technique */
@media (min-width: 10em) { --n: 1 }
@media (min-width: 20em) { --n: 2 }
@media (min-width: 30em) { --n: 3 }
The auto-fit Revelation
repeat() function wasn't behaving as expected, the documentation led to the auto-fit keyword. Despite unclear documentation, the potential for this problem was immediately apparent..grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8em, 1fr));
justify-content: center;
gap: 1em;
}
minmax() function also plays a critical role here. In this context, it creates the grid and then stretches the columns equally until they fill the available space.min() function to prevent overflow:grid-template-columns: repeat(auto-fit, minmax(min(8em, 100%), 1fr));
min() function does not work in pre-Chromium Edge browsers.Handling Panels and Sizing Variations
object-fit: cover solves the distortion problem while maintaining the visual structuregrid-column-end value — but you can use negative indices:.banner {
grid-column-end: -1; /* spans to the last column */
}
height is simple. Setting grid-column-end: -2 spans everything except the last column, and other negative values work similarly.Auto-fill vs. Auto-fit
auto-fill and auto-fit seem interchangeable — their documentation is dense, and swapping one for another can produce zero visual difference. The distinction emerges in specific scenarios:
minmax() column width like 8em, the two often produce identical results when there are enough items to require more than one rowminmax() column width rather than a fixed one, the results differjustify-content: center, auto-fill seems to be the more logical option, but auto-fit produces a better-looking result in certain configurations. The practical takeaway: if the grid uses a flexible minmax() column definition and contains only a few items, prefer auto-fill. The defaults strike the best balance with relatively simple rules, providing clean behavior across all these layout challenges without resorting to media query hacks or fragile pseudo-elements.



