Skip to main content
Builder’s Journal

Why Your CSS Grid Breaks on Mobile (and the One-Line Fix)

· · 4 min read

Why Your CSS Grid Breaks on Mobile (and the One-Line Fix)

If a CSS grid column overflows on phones and clips your content — text, tables or code cut off on the right, yet no horizontal scrollbar appears — the culprit is almost always a 1fr track that refuses to shrink. A grid 1fr column has an implicit min-width: auto, so a wide child (a table or a <pre> block) pushes the track wider than the screen, and an ancestor with overflow-x: hidden then clips the overflow instead of scrolling it. The fix is one property: min-width: 0 on the grid items (or minmax(0, 1fr) on the track).

What you’ll learn: why 1fr silently blows out, why your responsive breakpoints don’t save you, and the exact two changes that fix it — measured on a real layout.

Evidence note: based on a real overflow bug on my own WordPress site’s article template. The CSS shown is the live fix; the before/after widths are from a 375px viewport audit I ran on 2026-07-31.

The symptom

My single-post layout is a two-column grid — article on the left, sidebar on the right:

.mca-single-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
}

On desktop it’s perfect. On a 375px phone, the right edge of every paragraph, image and table was sliced off — and, confusingly, there was no horizontal scrollbar to hint at overflow. The content was just… gone past the right edge.

When I measured the article column at a 375px viewport, it was 571px wide — wider than the screen. Something inside it was forcing it open.

The fixes that didn’t work

  • "The breakpoint will handle it." I had a media query collapsing the grid to a single column on mobile. It fired — and the column was still 571px. Stacking the columns doesn’t help if one column refuses to be narrower than its widest child.
  • Hiding the overflow. An ancestor had overflow-x: hidden (a common "stop the page scrolling sideways" reflex). That’s exactly what turned an overflow into a clip: the content still rendered at 571px, but everything past the viewport edge was simply cut off with no way to reach it.

The root cause

This is the part that isn’t obvious. A grid track defined as 1fr doesn’t mean "take the remaining space and never exceed it." A 1fr track carries an implicit min-width: auto, and auto resolves to the min-content size of the track’s contents.

If any child can’t shrink below a certain width — a <table> with many columns, a <pre> block with a long line of code, a fixed-width image — then the track’s min-content is that width. The 1fr track dutifully grows to fit it, straight past the viewport. Add overflow-x: hidden on a parent and the excess is clipped instead of scrolled, so you get invisible, unreachable content and no scrollbar.

In short: 1fr will not shrink below its widest indivisible child unless you tell it it’s allowed to.

The fix

Two changes. The first is the one-liner that matters most.

1. Let the track shrink — min-width: 0. Override the implicit min-width: auto on the grid items:

.mca-single-layout > *,
.mca-single-article,
.mca-single-article__body,
.mca-single-sidebar {
  min-width: 0;
}

Equivalently, you can do it on the track itself with minmax(0, 1fr):

.mca-single-layout {
  grid-template-columns: minmax(0, 1fr) 320px;
}

Both say the same thing: this column is allowed to be narrower than its content’s min-content width.

2. Give wide children somewhere to go — scroll, don’t force. min-width: 0 lets the column shrink, but now a wide table would overflow the column. So wrap wide tables (and constrain <pre>) to scroll within their own box instead of pushing width outward:

.mca-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
  margin: 1.3rem 0;
}
.mca-single-article__body pre {
  min-width: 0;
}

Wrap each wide table:

<div class="mca-table-scroll">
  <table> … </table>
</div>

After both changes, the same article column at a 375px viewport measured 351px — down from 571px — with zero clipped elements. Tables now scroll inside their own container; everything else fits.

Why the obvious fixes fail

What you triedWhy it didn’t work
Add a mobile breakpointCollapsing to one column doesn’t remove the min-width: auto floor; the column stays as wide as its widest child.
overflow-x: hidden on a parentConverts the overflow into an invisible clip — worse than a scrollbar, because the content is unreachable.
width: 100% / max-width: 100% on the columnThe 1fr track’s min-content still wins; the track computes wider than 100% before your cap applies.

A reusable checklist

  1. Column overflowing on mobile? Add min-width: 0 to the grid items (or minmax(0, 1fr) to the track). This alone fixes most cases.
  2. Wrap wide tables in an overflow-x: auto container so they scroll instead of forcing width.
  3. Give <pre> blocks min-width: 0 (and let them scroll) for the same reason.
  4. Audit at 375px: check the computed width of the content column is ≤ viewport, and that nothing is clipped.
  5. Use overflow-x: hidden on the body as a last resort only — it hides symptoms and can clip real content.

Takeaway

1fr is not a promise to stay within bounds — it carries an implicit min-width: auto that lets one stubborn table or code block blow the whole column past the viewport, and overflow-x: hidden then hides the evidence. The moment a grid column overflows on mobile, reach for min-width: 0 (or minmax(0, 1fr)) first. It’s framework-agnostic — the same trap and the same fix apply whether you’re in WordPress, React, or plain HTML.

AI assisted with drafting; the layout, the bug, the fix, and the width measurements are from my own site.

Share this article

Leave a Reply

Your email address will not be published. Required fields are marked *