A two-column article layout looks simple:
- A sidebar on the left or right.
- The main article beside it.
- A sticky sidebar on desktop.
- Both columns collapse into a single column on mobile.
Yet this is one of those CSS layouts that can behave perfectly on a 1440px monitor and suddenly create a horizontal scrollbar on a 390px phone.
The problem is often not the obvious CSS. You may already have:
.article-layout {
display: grid;
grid-template-columns: 320px 1fr;
}The sidebar is 320px. The remaining space goes to the article. So why would the page overflow?
The answer is Grid's automatic minimum size. A long unbroken URL, a wide <table>, a code block, an image, or another element with an intrinsic width can prevent the 1fr track from shrinking as much as you expect.
This guide explains the problem, the reliable minmax(0, 1fr) fix, safe handling for long content, responsive tables, and how to keep position: sticky working without creating mobile overflow.
Understanding the CSS Grid Minimum-Size Trap
1. The Basic Two-Column Article Layout
Start with a straightforward semantic structure:
<div class="article-layout">
<aside class="article-sidebar">
<div class="sidebar-inner">
<h2>On This Page</h2>
<nav>
<a href="#introduction">Introduction</a>
<a href="#technical-seo">Technical SEO</a>
<a href="#performance">Performance</a>
<a href="#conclusion">Conclusion</a>
</nav>
</div>
</aside>
<main class="article-content">
<article>
<h1>Technical SEO Guide</h1>
<p>Your article content goes here.</p>
<!-- Tables, code blocks, images, etc. -->
</article>
</main>
</div>The initial CSS typically looks like this:
.article-layout {
display: grid;
grid-template-columns: 320px 1fr;
gap: 40px;
}On a large screen with simple paragraphs, this works fine. The problem starts when the main article contains content with a larger intrinsic minimum size than the available grid track.
2. The CSS Grid Trap: 320px 1fr
You might think: "The second column is 1fr, so it must shrink to fit the available width."
Not necessarily. Grid and Flexbox have automatic minimum sizing behavior. A grid item's automatic minimum size can be influenced by its content's intrinsic minimum width—such as a long unbroken URL or a multi-column table:
https://example.com/category/this-is-an-extremely-long-url-that-does-not-contain-any-breakable-spacesCertain descendants establish a minimum width that prevents the 1fr track from shrinking enough, pushing the main article past the right edge of the viewport.
3. Why 1fr Does Not Always Mean "Shrink to Zero"
1fr is shorthand for minmax(auto, 1fr). That auto minimum means the track refuses to shrink smaller than the minimum intrinsic width of its children (long URLs, unbroken strings, wide tables, preformatted code, or fixed-width embeds).
4. The minmax(0, 1fr) Fix
Instead of grid-template-columns: 320px 1fr;, use:
.article-layout {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 32px;
}minmax(0, 1fr) explicitly gives the flexible track a minimum of 0, telling the Grid track: "You are allowed to become as narrow as zero rather than preserving an automatic minimum based on the content."
320px 1fr
Horizontal Page Scrollbar
320px minmax(0, 1fr)
Contained Inside Viewport
320px 1fr overflows due to intrinsic content width while 320px minmax(0, 1fr) locks the column inside the viewport.5. Apply min-width: 0 to Grid Items and Nested Grids
Pair minmax(0, 1fr) on the parent track with min-width: 0 on the grid item itself:
.article-layout {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 32px;
}
.article-content {
min-width: 0;
}minmax(0, 1fr)controls the grid track.min-width: 0;allows the grid item itself to shrink below its content's intrinsic width.
Handling Long Strings, Tables, and Overflow Traps
6. Handle Long URLs and Unbroken Content
Allow long strings and URLs to wrap instead of overflowing their container:
.article-content {
overflow-wrap: break-word;
}
.article-content a {
overflow-wrap: break-word;
}
.article-content code {
overflow-wrap: anywhere;
}7. Wrap Wide Tables in a Local Horizontal Scroll Container
Shrinking every table column until text squishes vertically is unreadable. Instead, wrap the table in a container with overflow-x: auto:
<div class="table-wrapper">
<table>
...
</table>
</div>.table-wrapper {
max-width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.table-wrapper table {
width: 100%;
min-width: 650px;
border-collapse: collapse;
}.table-wrapper handles horizontal swipe:
| Keyword | Search Intent | Monthly Searches | Competition | Recommended Page |
|---|---|---|---|---|
| technical SEO audit | Commercial | 1,000 | High | /technical-seo-audit/ |
8. Do Not Use body { overflow-x: hidden } as Your First Fix
Putting overflow-x: hidden on body hides the scrollbar by clipping content off-screen (making 610px of a 1000px element completely unreachable on a 390px phone). Fix the intrinsic width at the source instead.
Sticky Sidebars & Responsive Breakpoints
9. Add the Sticky Sidebar With align-items: start
Make the inner sidebar sticky and set align-items: start on the grid container so the sidebar track doesn't stretch to full height:
.article-layout {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 32px;
align-items: start;
}
.article-content {
min-width: 0;
overflow-wrap: break-word;
}
.sidebar-inner {
position: sticky;
top: 24px;
}10. Avoid Ancestor overflow Rules That Break position: sticky
Adding overflow: hidden or overflow: auto to .article-layout or parent wrappers alters the scrolling context and breaks position: sticky. Apply overflow-x: auto only to specific child wrappers like .table-wrapper and pre.
11. Collapse the Layout and Reset Sticky on Tablet and Mobile
Collapse the grid to a single column below 900px and reset the sidebar to position: static so it doesn't cover the screen while scrolling on mobile:
@media (max-width: 900px) {
.article-layout {
grid-template-columns: minmax(0, 1fr);
}
.sidebar-inner {
position: static;
}
}grid-template-columns: 320px minmax(0, 1fr) with .sidebar-inner { position: sticky; top: 24px; }.
grid-template-columns: minmax(0, 1fr) with .sidebar-inner { position: static; } stacked above article.
12. Assemble the Complete Defensive CSS Component
.article-layout {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 32px;
align-items: start;
}
.article-sidebar {
min-width: 0;
}
.sidebar-inner {
position: sticky;
top: 24px;
}
.article-content {
min-width: 0;
max-width: 100%;
overflow-wrap: break-word;
}
.article-content img,
.article-content video,
.article-content iframe {
max-width: 100%;
height: auto;
}
.table-wrapper {
width: 100%;
max-width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.table-wrapper table {
width: 100%;
min-width: 650px;
border-collapse: collapse;
}
.article-content pre {
max-width: 100%;
overflow-x: auto;
}
.article-content code {
overflow-wrap: anywhere;
}
@media (max-width: 900px) {
.article-layout {
grid-template-columns: minmax(0, 1fr);
}
.sidebar-inner {
position: static;
}
}Debugging & Production Verification
13. Understand Why width: 100% Alone Does Not Solve Everything
Setting .article-content { width: 100%; } does not override the parent Grid sizing algorithm if the track is still defined as 1fr. You must pair minmax(0, 1fr) on the grid track with min-width: 0 on the grid item.
14. Debug Unexpected Horizontal Scrollbars in DevTools
When a mobile page develops horizontal scrolling, inspect at the exact viewport width where it breaks or temporarily apply:
* {
outline: 1px solid red;
}Compare the computed width of <table>, <pre>, <code>, <iframe>, and long URLs against the containing block (and remove the outline before shipping).
15. Follow the 7-Question Debugging Sequence
- Is the Grid track allowed to shrink (
minmax(0, 1fr))? - Can the Grid item itself shrink (
min-width: 0)? - Is there an unbreakable string (
overflow-wrap: break-word)? - Is a table wider than the article (
.table-wrapper { overflow-x: auto })? - Is an image or iframe wider than its parent (
max-width: 100%)? - Is the sidebar still sticky on a narrow viewport (
position: static)? - Did an ancestor create an unexpected scrolling context?
16. Add Local Horizontal Scrolling for Code Blocks
For multi-line code blocks, character-by-character wrapping hurts readability. Let <pre> scroll horizontally inside its own box:
.article-content pre {
max-width: 100%;
overflow-x: auto;
}17. Standardize the Predictable Production Pattern
Keep your base layout CSS boring and predictable so authors can publish any combination of tables, code snippets, and links without breaking mobile viewports.
18. Verify the 15-Point Final Responsive CSS Checklist
minmax(0, 1fr) for the article columnmin-width: 0<pre>) scroll independentlyposition: sticky on desktoptop offsetbody { overflow-x: hidden }Conclusion
The most frustrating part of responsive CSS overflow is that the layout can look completely correct until one piece of real content exposes the weakness.
Replace grid-template-columns: 320px 1fr; with the defensive grid-template-columns: 320px minmax(0, 1fr);, set min-width: 0 and overflow-wrap: break-word on the article container, isolate wide tables and <pre> blocks inside overflow-x: auto wrappers, and reset sticky sidebars to position: static on mobile.
The key lesson is that responsive design is not just about adding media queries—you have to control the minimum dimensions of the content inside the layout as well.
What is the most stubborn responsive-layout bug you've encountered in a content-heavy website?