Common CSS Layout Traps Developers Hit
CSS layout has evolved significantly with Flexbox and Grid, but certain behaviors continue to surprise developers. These traps often stem from misunderstanding how browsers calculate sizes or how properties interact.
This guide covers the most common layout traps and their solutions.
Problem
Developers frequently encounter:
- Elements not sizing as expected
- Overflow appearing unexpectedly
- Spacing behaving inconsistently
- Layouts breaking at certain content lengths
Each of these has a logical explanation once you understand the underlying CSS algorithms.
Why It Happens
CSS layout is deterministic, but the rules are numerous and interact in complex ways. Properties that seem independent often affect each other through the box model, flex calculations, or grid sizing algorithms.
Solution
Learn the specific traps and their fixes. Here are the most common ones:
Trap 1: Flexbox Items Not Shrinking
.container {
display: flex;
}
.item {
flex: 1;
/* Item does not shrink below content size */
}
Flex items have min-width: auto by default, preventing them from shrinking below their content size.
Fix:
.item {
flex: 1;
min-width: 0;
}
Trap 2: Text Not Wrapping in Flex Items
.card {
display: flex;
}
.card-content {
/* Long text does not wrap, overflows container */
}
Same cause as above—the flex item cannot shrink.
Fix:
.card-content {
min-width: 0;
overflow-wrap: break-word;
}
Trap 3: Images Breaking Layout
.container {
display: flex;
}
img {
/* Image causes container to expand unexpectedly */
}
Images have intrinsic dimensions that affect flex calculations.
Fix:
img {
max-width: 100%;
height: auto;
flex-shrink: 0; /* Or min-width: 0 depending on intent */
}
Trap 4: Margin Collapse Surprises
.parent {
margin-top: 20px;
}
.child {
margin-top: 30px;
/* Margin collapses with parent */
}
Vertical margins collapse in block formatting contexts. The child's margin can "escape" the parent.
Fix:
.parent {
padding-top: 1px; /* Prevents collapse */
/* Or: display: flex | grid | flow-root */
}
NOTE: Margin collapse does not occur in flex or grid containers, or when the parent has padding, border, or overflow (other than visible).
Trap 5: 100vh on Mobile
.hero {
height: 100vh;
/* On mobile, this is taller than the visible viewport */
}
Mobile browsers have dynamic toolbars that are not accounted for in vh units.
Fix:
.hero {
height: 100dvh; /* Dynamic viewport height */
}
/* Fallback for older browsers */
@supports not (height: 100dvh) {
.hero {
height: 100vh;
}
}
Trap 6: Position Sticky Not Working
.sidebar {
position: sticky;
top: 0;
/* Does not stick */
}
An ancestor has overflow: hidden, auto, or scroll.
Fix:
Check and remove overflow on ancestors, or use overflow: clip instead of hidden.
Trap 7: Gap Not Working on Flex
.container {
display: flex;
gap: 1rem;
/* gap does nothing in older browsers */
}
Flex gap is supported in all modern browsers but not IE11 or older Safari.
Fix:
.container {
display: flex;
gap: 1rem;
}
/* Fallback */
.container > * + * {
margin-left: 1rem;
}
Example
A complete card component avoiding common traps:
.card {
display: flex;
flex-direction: column;
min-height: 0; /* Allow shrinking */
}
.card-image {
width: 100%;
height: auto;
object-fit: cover;
flex-shrink: 0;
}
.card-content {
flex: 1;
min-width: 0; /* Allow text to wrap */
padding: 1rem;
}
.card-title {
overflow-wrap: break-word;
word-break: break-word;
}
.card-description {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
Common Mistakes
Using fixed heights
/* Bad - breaks with different content */
.card {
height: 300px;
}
/* Good - adapts to content */
.card {
min-height: 300px;
}
Assuming box-sizing
Different elements have different default box-sizing:
/* Reset for consistency */
*, *::before, *::after {
box-sizing: border-box;
}
Using percentage widths without context
.child {
width: 50%;
/* 50% of what? Parent must have a defined width */
}
WARNING: Percentage widths require a containing block with a defined size. If the parent's width depends on content, percentage children cannot calculate their own width.
Conclusion
Most CSS layout traps involve flex/grid item sizing, overflow interactions, or implicit browser defaults. Add min-width: 0 and min-height: 0 to flex/grid items, understand margin collapse rules, and use dvh units for mobile viewports. When layouts break unexpectedly, check for overflow on ancestors and verify box-sizing is consistent.