Gap, order and flex-basis instead of media query hacks
A sidebar layout made of a fixed side column and a flexible main area sounds like a trivial task, yet it regularly breaks on long words, overflowing content and missing media queries. Flexbox delivers a solution through flex-basis, gap and the sidebar pattern that wraps automatically with no breakpoints at all, and controls visual order independently of the source code.
Table of Contents
- 1. Why Sidebar Layouts Are Still Needed
- 2. Base Structure: the Flex Container for Sidebar and Main Area
- 3. Combining flex-grow, flex-shrink and flex-basis Correctly
- 4. Gap Instead of Margin: Spacing Between Sidebar and Content
- 5. Automatic Wrapping With the Sidebar Pattern
- 6. The order Property and Its Keyboard Pitfalls
- 7. Multiple Sidebars: Combining Left and Right Columns
- 8. The min-width Zero Pitfall With Overflowing Content
- 9. Flexbox Sidebar Layout Compared to Grid
- 10. Summary
- 11. FAQ
1. Why Sidebar Layouts Are Still Needed
A sidebar layout made of a narrow side column and a wide main content area is one of the most frequently recurring structures on the web, from documentation pages with navigation on the left to product pages with a filter column. Unlike a full page layout with header and footer, a sidebar layout is usually about exactly two adjacent regions whose ratio should stay flexible: the sidebar has a preferred width, the main area fills the remaining space.
Flexbox often suits this one dimensional problem better than Grid, because no two dimensional grid is needed, only a distribution along a single axis. A well built sidebar layout with Flexbox needs neither fixed pixel widths nor a media query to wrap sensibly on narrow screens, once you know the right combinations of flex-basis, flex-grow and flex-wrap. Those combinations are exactly what this article focuses on.
2. Base Structure: the Flex Container for Sidebar and Main Area
The starting point for every sidebar layout with Flexbox is a container with display: flex, which by default arranges items along the horizontal axis. The sidebar and the main area are inserted as direct children, and their width is controlled not through width but through the three flex properties flex-grow, flex-shrink and flex-basis. That is the most important conceptual difference from a block layout: Flexbox distributes available space instead of simply positioning boxes next to each other.
In practice, a minimal container with two children is enough for a simple sidebar layout. The sidebar gets a fixed flex-basis, say 260 pixels, and flex-shrink: 0, so it does not shrink when space is tight but the wrap kicks in instead. The main area gets flex-grow: 1 to fill all remaining space. This simple structure is the foundation every following refinement builds on.
/* Base flex container for the sidebar layout */
.layout {
display: flex;
align-items: flex-start; /* sidebar and main do not stretch to equal height */
}
.sidebar {
flex: 0 0 260px; /* grow 0, shrink 0, basis 260px - fixed width */
}
.main {
flex: 1 1 0%; /* grow 1, shrink 1, basis 0 - fills remaining space */
}
3. Combining flex-grow, flex-shrink and flex-basis Correctly
The flex shorthand bundles three values that each take on their own role in a sidebar layout. flex-grow determines how much extra free space an element receives relative to its sibling elements. flex-shrink determines how much an element shrinks when the available space is insufficient. flex-basis is the starting size from which growing and shrinking are calculated, comparable to a preferred width before remaining space is distributed.
A common mistake in a sidebar layout is giving the sidebar only width: 260px without setting flex-shrink: 0. Without that flag, the sidebar still shrinks under tight space, because the flex algorithm applies flex-shrink: 1 to all children by default. The result: a sidebar that unexpectedly narrows at medium screen widths, even though a fixed width was actually intended. Explicit flex-shrink: 0 on the sidebar reliably fixes this behavior.
4. Gap Instead of Margin: Spacing Between Sidebar and Content
Historically, spacing in a sidebar layout was created via margin-right on the sidebar or margin-left on the main area. That works in the simple case but becomes unwieldy as soon as more than two child elements sit in the container, or once the order changes later via order, because margin values then end up on the wrong side. The gap property solves this at the root: defined once on the flex container, it automatically produces correct spacing between all direct children, regardless of their number or order.
For a sidebar layout with variable wrapping behavior, gap is practically indispensable, because the same value applies both to the horizontal spacing in the side by side state and to the vertical spacing after a wrap. A single gap: 2rem value is therefore enough for both layout states, with no extra media query just for spacing.
/* gap replaces margin-based spacing entirely */
.layout {
display: flex;
align-items: flex-start;
gap: 2rem; /* works both side by side and stacked after wrapping */
}
5. Automatic Wrapping With the Sidebar Pattern
The best known advanced sidebar layout recipe with Flexbox uses flex-wrap combined with a deliberately chosen flex-basis to wrap without any media query at all. The trick: the main area gets a very large flex-grow number such as 999 and flex-basis: 0, while the sidebar gets a normal flex-grow: 1 and a minimum desired width through flex-basis. As long as there is enough space, the main area's high flex-grow value dominates completely, and the sidebar stays at its flex-basis width. As soon as the available space drops below the sum of both flex-basis values, flex-wrap: wrap kicks in and the sidebar automatically drops into its own line.
This sidebar layout recipe, often called the sidebar pattern, does not react to viewport width like a media query does, but to the space actually available inside the container. That makes it especially robust in nested components, for example when the same sidebar structure is reused once at full width and once inside a narrow column. A classic media query would check the wrong reference value in that case, while Flexbox's container based wrapping behavior would not.
/* The Sidebar Pattern: no media query needed for the reflow */
.layout {
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
.sidebar {
flex-grow: 1;
flex-basis: 260px; /* preferred width before wrapping kicks in */
}
.main {
flex-grow: 999; /* dominates all available space when there is room */
flex-basis: 0;
min-inline-size: 60%; /* forces a wrap earlier if main gets too narrow */
}
6. The order Property and Its Keyboard Pitfalls
The order property lets you determine the visual order of child elements in a sidebar layout independently of their position in the HTML. A default value of 0 applies to all elements without an explicit value, a lower value moves an element further forward, a higher value further back. That lets, for example, main content that appears first in the source for SEO reasons still show up visually to the right of the sidebar.
The decisive pitfall with order in a sidebar layout: the tab order for keyboard users still follows the DOM, not the visual order. Anyone navigating the page via the tab key jumps through the original source order, even if the sidebar appears visually first. For purely decorative reordering that is unproblematic, but for interactive elements such as navigation links inside the sidebar it can lead to confusing tab order and should be tested with real keyboard users before going into production.
7. Multiple Sidebars: Combining Left and Right Columns
A sidebar layout with two side columns, for example navigation on the left and a table of contents on the right, follows the same base pattern with three children instead of two in the flex container. Both sidebars get a fixed flex-basis and flex-shrink: 0, and the main area in the middle takes on the remaining space as usual with flex-grow: 1. The order property then controls, independently of HTML order, which column appears on the left and which on the right.
With three columns, however, wrapping behavior with flex-wrap becomes more complex, because leaving the side by side state means all three elements land in some order stacked on top of each other. For a sidebar layout with two side columns, an explicit breakpoint is therefore often preferable to the automatic sidebar pattern, because the desired stacked order, for example main content first, then both sidebars, remains hard to predict with pure container based wrapping.
8. The min-width Zero Pitfall With Overflowing Content
A subtle but common bug in every sidebar layout with Flexbox: long words, wide code blocks or images in the main area burst the container, even though flex-grow and flex-basis are set correctly. The reason lies in the initial value of min-width for flex children, which defaults to auto. That means a flex child can never become smaller than its own content, even when flex-shrink should apply.
The fix for this issue in a sidebar layout is to explicitly set min-width: 0 on the main area. That allows the element to become smaller than its intrinsic content, so text wraps and long lines of code scroll inside their own overflow container instead of bursting the entire layout. This single line CSS fix gets overlooked so often in practice that it counts among the best known Flexbox debugging tricks.
/* Prevent long content from breaking the layout */
.main {
flex: 1 1 0%;
min-width: 0; /* without this, intrinsic content width wins over flex-shrink */
overflow-x: auto; /* wide code blocks scroll inside main instead of overflowing */
}
9. Flexbox Sidebar Layout Compared to Grid
Both Flexbox and CSS Grid can implement a sidebar layout, but they differ noticeably in approach and use case. The following table shows which technique is the better choice, and when.
| Task | Flexbox Approach | Grid Approach | Recommendation |
|---|---|---|---|
| Two columns, one dimensional | flex-basis plus flex-grow |
grid-template-columns |
Flexbox, simpler for one axis |
| Wrapping without media query | Sidebar pattern with flex-wrap |
auto-fit plus minmax() |
Flexbox, more precise with two items |
| Equal height of sidebar and content | Only with align-items: stretch |
Automatic through the grid row | Grid, when height matters |
| More than two columns with a fixed structure | Wrapping hard to predict | grid-template-areas |
Grid for three or more regions |
| Spacing between elements | gap on the flex container |
gap on the grid container |
Both equally good |
In practice, the choice rarely comes down to the technique alone, but to whether height matters and whether the sidebar layout stays limited to exactly two regions. For the most common case, one sidebar and one main area, Flexbox delivers a solution just as robust as Grid with less code.
Mironsoft
Frontend architecture, layout systems and modern CSS implementation
A sidebar layout that works at every width?
We build Flexbox and Grid based layout systems that avoid media query sprawl, consistently respect accessibility, and hold up reliably with variable content lengths.
Layout Audit
Reviewing existing sidebar layouts for Flexbox pitfalls
Responsive Refactoring
Replacing media query sprawl with container based wrapping behavior
Accessibility Check
Testing tab order with real keyboard users after order changes
10. Summary
A robust sidebar layout with Flexbox rests on a handful of clearly understood building blocks: flex-basis defines the preferred width, flex-grow and flex-shrink control behavior when extra or insufficient space is available, and gap handles spacing cleanly for both layout states. The sidebar pattern, with a high flex-grow on the main area and flex-wrap on the container, produces automatic wrapping that reacts to the actually available space instead of being rigidly tied to a viewport width.
Two details decide in practice between success and recurring bugs in a sidebar layout: min-width: 0 on the main area prevents long content from bursting the entire layout, and the order property must never be used without testing tab order for keyboard users. Anyone who knows these rules can build a sidebar layout that avoids media query sprawl and works just as reliably in nested components as at the top level of a page.
Sidebar Layouts With Flexbox — The Essentials at a Glance
Base structure
flex-basis plus flex-shrink: 0 on the sidebar, flex-grow: 1 on the main area.
Sidebar pattern
A high flex-grow value on the main area plus flex-wrap produces wrapping with no media query.
Common pitfalls
Missing min-width: 0 bursts the layout with long content, order does not change tab order.
Spacing
gap on the container replaces margin hacks and works in both wrapping states.