Responsive grid without media queries
Four grid recipes that reflow on their own, using auto-fit, minmax and container queries.
<section>
<h2>1. Equal columns that wrap on their own</h2>
<p class="note">auto-fit + minmax. Cards never go below 180px; the count adjusts.</p>
<div class="g ram">
<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>
</div>
</section>
<section>
<h2>2. A wide first item</h2>
<p class="note">One rule promotes the first card to full width.</p>
<div class="g ram feature">
<div>Featured</div><div>2</div><div>3</div><div>4</div>
</div>
</section>
<section>
<h2>3. Sidebar that drops below when space runs out</h2>
<p class="note">A flex recipe: the sidebar keeps its width until the content column hits its minimum.</p>
<div class="sidebar">
<div class="side">Sidebar 220px</div>
<div class="body">Content, minimum 340px</div>
</div>
</section>
<section>
<h2>4. Asymmetric rows that stay aligned</h2>
<p class="note">Named lines, so the shape is readable in the CSS.</p>
<div class="g mosaic">
<div class="tall">Tall</div><div>A</div><div>B</div><div class="wide">Wide</div>
</div>
</section>* { box-sizing: border-box; margin: 0; }
body { font: 16px/1.6 system-ui, -apple-system, sans-serif; background: #f6f8fb; padding: 22px; }
section { margin-bottom: 28px; }
h2 { font-size: 1.02rem; color: #16202e; }
.note { font-size: .84rem; color: #8593ab; margin: 3px 0 12px; }
/* ============ 1. the "RAM" recipe ============
Repeat, Auto-fit, Minmax. The single most useful line in CSS grid. */
.ram {
display: grid;
gap: 12px;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
/* ============ 2. promote one item ============ */
.feature > :first-child { grid-column: 1 / -1; }
/* ============ 3. sidebar that wraps ============
Flex, not grid: the sidebar holds 220px until the content column
would drop below 340px, then both go full width. */
.sidebar { display: flex; flex-wrap: wrap; gap: 12px; }
.sidebar .side { flex-grow: 1; flex-basis: 220px; }
.sidebar .body { flex-grow: 999; flex-basis: 340px; }
/* ============ 4. named lines ============ */
.mosaic {
display: grid;
gap: 12px;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-auto-rows: 84px;
}
.mosaic .tall { grid-row: span 2; }
.mosaic .wide { grid-column: span 2; }
/* demo chrome */
.g > div, .sidebar > div {
display: grid;
place-items: center;
background: #fff;
border: 1px solid #e2e7ef;
border-radius: 9px;
padding: 18px;
font-size: .88rem;
color: #5b6b83;
}
.feature > :first-child, .mosaic .tall, .mosaic .wide { background: #eef0fe; border-color: #c9d1fb; color: #2a3abf; }
.sidebar .side { background: #eef0fe; border-color: #c9d1fb; color: #2a3abf; }How it works
Media queries respond to the viewport. Most layout problems are actually about the space a component has, which is not the same thing — a card in a sidebar and the same card full width both need to reflow, and the viewport width tells you nothing about either.
The RAM recipe. repeat(auto-fit, minmax(180px, 1fr)) — Repeat, Auto-Fit, Minmax. It fits as many 180-pixel columns as will go, then stretches them to fill the row. Six items, four items, one item: it adapts, at every width, with no breakpoints.
auto-fit versus auto-fill. With fewer items than columns, auto-fit collapses the empty tracks and stretches what is there; auto-fill keeps the empty tracks and leaves a gap. Use auto-fit for a gallery of unknown length, auto-fill when you want items to stay a consistent size regardless of how many there are.
grid-column: 1 / -1 spans an item from the first line to the last, whatever the column count happens to be at that width. That is how you feature one card without knowing how many columns there will be.
The flex sidebar. flex: 999 1 340px on the content gives it an enormous grow factor, so it takes essentially all the spare space while the sidebar keeps its basis. When the content would drop below its 340-pixel basis, both wrap. This is Heydon Pickering's "sidebar" pattern and it is the one flexbox recipe grid genuinely cannot replicate.
span for asymmetry. grid-row: span 2 and grid-column: span 2 give you a mosaic without fixed positions, so it still reflows.
Accessibility notes
Grid and flex both reorder content visually without changing the DOM. That is powerful and it is a trap: tab order and screen reader order follow the source, so a visually reordered layout can produce a tab sequence that jumps around the page.
Keep the source order matching the logical reading order, and use grid placement for visual arrangement only. If you find yourself needing a large reorder, the fix is usually to change the markup, not to fight it with order.
Making it yours
The minmax minimum is the number to tune. Too small and you get six cramped columns on a desktop; too large and you drop to one column too early. Somewhere between 180 and 280 pixels covers most card layouts.
One caveat: with minmax(180px, 1fr), a container narrower than 180 pixels will overflow. minmax(min(180px, 100%), 1fr) fixes it, at the cost of a longer line.
Container queries take this further — @container (min-width: 400px) responds to the component's own width rather than the viewport's, which is what you actually wanted all along. Support is now good across current browsers.
Related templates
Holy grail layout
Header, footer, two sidebars and a main column — in nine lines of grid.
HTMLCSSCentering recipes
Six ways to centre something, and which one to use when.
HTMLCSSSticky footer
A footer that sits at the bottom of the viewport on short pages and below the content on long ones.
HTMLCSSJavaScriptResponsive navbar
A header that collapses to a hamburger under 820px. No framework, keyboard accessible.
HTMLCSSJavaScriptTailwindCheck your version
Once you have edited this, the HTML validator will catch any tag you left unclosed, and the formatter will tidy the indentation. Both run in your browser.