D
P
0

HTML & CSS

Product Cards Shrink to 240px on Desktop? A `display:none` Grid Item Breaks Column Auto-Placement

July 7, 2026·4 min read
Product Cards Shrink to 240px on Desktop? A `display:none` Grid Item Breaks Column Auto-Placement

On a client store's collection page, the product-cards area suddenly rendered tiny on desktop. Not merely narrow, but genuinely small, about 240px, squeezed against the left edge while the rest of the page width sat empty. The client kept reporting it with the same line: "product card very small." I opened DevTools, inspected the product CSS, and nothing looked wrong. No odd max-width, no tiny flex-basis, no hardcoded width. Everything I looked at seemed correct, yet the result was clearly not.

My first instinct was a bad one, as usual. I assumed a leaking media query, or a container query with the wrong breakpoint, or maybe a plugin !important overriding the card width. I toggled off every suspicious rule in the Styles panel one by one. Nothing moved that 240px by a single pixel. The card stubbornly clung to that width, as if 240px were its destiny.

Why this happens

It only clicked once I stopped staring at the card CSS and started looking at its container. The page layout was a two-column grid:

.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
}
.sidebar {
  display: none;
}

That 240px was not the card's width. It was the width of the grid's first track, the one the sidebar was meant to occupy. And there was the trap. The sidebar was the first child of the grid, but it was set to display: none. When a grid item is set to display: none, it is not merely hidden visually. It is pulled entirely out of the grid's auto-placement queue, as if it never existed.

So the grid recalculated. Its track template was still 240px 1fr, two columns, that never changed. But now there was only one child left, the products area. Auto-placement drops the first available child into the first available cell, and the first cell is the 240px column. So the products area, which I had pictured sitting comfortably in the 1fr column, got crammed into the 240px track instead. The wide 1fr column was left empty, because there was no second child to fill it.

Nothing was actually broken in the product CSS. What was broken was my assumption that display: none merely hides the sidebar without touching the grid's geometry. In fact it rewrote the placement queue for the whole grid.

The fix

The core rule I have held onto since: do not pair display: none with a fixed first track. If the first child can disappear, the first track must not carry a fixed width that traps whatever child lands there next.

My favorite approach is to gate the columns with :has(). Default to a single column, and only produce the two-column template when the sidebar is actually open:

.layout {
  display: grid;
  grid-template-columns: 1fr;
}
.layout:has(.sidebar.is-open) {
  grid-template-columns: 240px 1fr;
}

This way, when the sidebar is absent, the grid has a single 1fr track and the products area fills the full width correctly. The phantom 240px track is never created, so there is nothing left to squeeze anyone into.

If I need the sidebar to always exist in the DOM but be hidden sometimes, I pin the content to an explicit column so it can never drift into the first cell:

.content-wrap {
  grid-column: 2;
}

The third option, and often the cleanest in a templating environment, is to render the sidebar conditionally server-side, for example in Liquid, so the grid genuinely has only one child when the sidebar is not in use. If the element truly is not there, there is no display: none to worry about, and auto-placement has no surprises to hand you.

The takeaway

display: none on a grid item is not a cosmetic operation. It removes the item from the auto-placement queue, and the remaining children reflow into the available cells starting at the first one. If your first track is fixed and narrow, the child that flows into it shrinks too, and you will burn time inspecting the CSS of the wrong element. When an element renders at a strangely specific width like 240px, do not rush to suspect that element's own CSS; ask first whether that number came from a track on its parent grid. Since this one, the moment I see a suspicious width match one of the template tracks, I climb one level up to the container and ask: who was supposed to fill this cell, and where did they go?