Stacking Email Columns Without Media Queries
Build columns that reflow from width alone: inline-block with max-width, the ghost table for Outlook, whitespace control, and why this survives clients that strip CSS.
A two-column layout that stacks through a media query renders as two squeezed columns wherever that query is stripped — most visibly in the Gmail app on a non-Google account. This guide builds columns that reflow from their own widths, so the mobile layout is the default rather than an enhancement.
Root Cause: The Query Is an Enhancement, Not the Mechanism
A media-query layout has its correct mobile rendering conditional on CSS surviving the journey. When the embedded style block is removed, the fallback is the desktop layout at phone width: two 300px columns inside a 320px viewport, each with its content compressed to unreadability.
The alternative inverts the dependency. Columns declared as inline-block with a percentage width and a min-width reflow purely from the space available: while the row is wide enough for both, they sit side by side; when it is not, the second wraps below the first. No CSS beyond the inline styles is required, and inline styles survive everywhere.
The trade is that you give up precise control of the breakpoint. Reflow happens when the content no longer fits rather than at a width you chose, which is usually close enough and occasionally not. A media query can still be layered on top to refine spacing and type at narrow widths — but the layout is already correct without it.
The Exact Pattern
Three parts: a ghost table for the Word engine, inline-block columns with a percentage width and a minimum, and whitespace control between them.
<!--[if mso]>
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0"><tr><td>
<![endif]-->
<!-- The outer div is fluid up to 600px. Outlook never sees it as fluid,
because the ghost table above has already pinned the width. -->
<div style="max-width:600px;margin:0 auto;">
<!--[if mso]><table role="presentation" width="100%"><tr><td width="50%" valign="top"><![endif]-->
<!-- Column A. width:100% with max-width and min-width is the whole mechanism:
while the row fits 2 x 280px it stays inline; below that it wraps.
Affects every client that honours inline styles, which is all of them. -->
<div style="display:inline-block;vertical-align:top;
width:100%;max-width:280px;min-width:240px;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td style="font-family:Arial,sans-serif;font-size:16px;line-height:24px;
mso-line-height-rule:exactly;padding:12px;">
Column A content.
</td></tr>
</table>
</div><!--
--><!--[if mso]></td><td width="50%" valign="top"><![endif]-->
<!-- The comment above spans the newline between the two divs. Without it the
whitespace renders as a space character and 50% + space + 50% overflows. -->
<div style="display:inline-block;vertical-align:top;
width:100%;max-width:280px;min-width:240px;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td style="font-family:Arial,sans-serif;font-size:16px;line-height:24px;
mso-line-height-rule:exactly;padding:12px;">
Column B content.
</td></tr>
</table>
</div>
<!--[if mso]></td></tr></table><![endif]-->
</div>
<!--[if mso]>
</td></tr></table>
<![endif]-->
The min-width is what actually triggers the stack. Without it, two 100%-width inline-blocks each capped at 280px would simply shrink to half the available width and stay side by side at any size. With it, the browser cannot place both on one row once the row falls below roughly 480px, so the second wraps.
The <!-- --> comment spanning the newline is not decoration. Whitespace between inline-block elements renders as a space character with real width, and 280 + space + 280 exceeds 560 — so without it the columns wrap at a width where they should still fit.
Choosing the Widths
Three numbers interact, and getting them wrong produces a layout that stacks too early or never stacks at all.
| Value | Purpose | Typical |
|---|---|---|
Container max-width |
The desktop content width | 600px |
Column max-width |
Half the container, minus padding | 280px |
Column min-width |
The width below which stacking must happen | 240px |
The relationship that matters is that twice the min-width must exceed the narrowest width at which you still want two columns. With a 240px minimum, two columns need 480px, so anything below that stacks — which lands neatly between phone widths and the 600px desktop width. Raising the minimum stacks earlier; lowering it allows two very narrow columns, which is rarely what anyone wants.
Variant: Three Columns and Uneven Splits
Three columns work identically with a smaller minimum — 180px gives a threshold of 540px, so three columns become one below that. What three columns do not do is reflow to two: inline-block wrapping is all-or-nothing per element, so the third wraps alone and produces a 2-then-1 arrangement that usually looks unintentional. Where a 2-then-1 layout is wanted, build it as two rows.
Uneven splits — a 2:1 content-and-sidebar arrangement — work by giving each column a different max-width while keeping the minimums proportional. The Outlook ghost table's width attributes must match the same ratio, since the Word engine takes its widths from the ghost table and not from the CSS.
Content That Resists Reflow
The pattern handles text and buttons well. Three kinds of content need extra care, because each has an intrinsic width that does not shrink.
Images must be fluid or they set a floor under the column width. An image declared at a fixed 280px inside a column with a 240px minimum will not let the column go below 280px, so the stacking threshold silently moves and the layout wraps later than intended. Declaring width: 100%; max-width: 280px; height: auto on the image lets it shrink with its column while keeping its aspect ratio and its ceiling.
Long unbroken strings — a tracking number, a URL printed as text, an email address — establish a minimum width equal to their rendered length. A 40-character reference in a 240px column pushes it wider and can prevent stacking entirely. Adding word-break: break-word lets the string wrap; where breaking it mid-token would be confusing, shortening the visible text and linking the full value is the better answer.
Tables of figures are the hardest case, because a table's minimum width is the sum of its columns' minimum widths and no CSS makes that smaller. A four-column table inside a two-column layout will usually force the row wider than the viewport. The workable answers are to give the table its own full-width row outside the column structure, or to restructure it as label-and-value pairs that stack naturally.
The common thread is that reflow depends on every element in the column being willing to shrink. One element that is not — an image with a fixed width, a long token, a wide table — overrides the whole mechanism, and the symptom is a layout that works in every test until the one message where a customer's order reference is two characters longer.
Pipeline Integration
Express the pattern as a component with a column count and an optional ratio, not as markup copied between templates. The whitespace comment in particular is the kind of detail that survives one copy and is lost on the second, and its absence produces a bug that looks like a width miscalculation rather than a whitespace problem.
Add a horizontal-overflow check at mobile width to the QA pass. A layout that fails to stack overflows the viewport, which is mechanically detectable in a headless browser and much faster than reading screenshots.
Validation and Deployment Checklist
Frequently Asked Questions
Can I still use a media query on top of this?
Yes, and you usually should — for type size, padding and image widths at narrow viewports. The distinction is that the query refines a layout that is already correct rather than creating it. If removing the query breaks the layout rather than merely coarsening it, the dependency is the wrong way round.
Why not use float?
The Word engine ignores float entirely, so a float-based layout needs the ghost table to do all the work in Outlook and provides no reflow at all in clients that strip CSS. Inline-block is honoured more widely and reflows on its own, which is the property being relied on.
Does this work in the Gmail Android app on a non-Google account?
Yes — that is the specific case it is built for. Inline styles survive, the widths are inline, and the reflow needs nothing else. This is the main practical reason to prefer it over a query-based layout.
What about vertical spacing between stacked columns?
Apply it as padding inside each column rather than as a margin between them. Padding is honoured consistently and produces the same gap whether the columns are side by side or stacked, whereas a bottom margin that is correct when stacked adds unwanted space when they are not.
Related
- Responsive Email Layouts — where this pattern sits among the strategies
- Fixing Gmail App Media Query Stripping — the client behaviour this pattern is designed around
- Outlook Rendering Fixes — the ghost table this layout depends on
- CSS Media Queries for Mobile Email Clients — the enhancement layer applied on top
← Back to Responsive Email Layouts