Layout bugs in CSS rarely come from ignorance. They come from habits learned early, when the toolkit was floats, absolute positioning and a careful stack of margins. Those methods still work, but they need constant upkeep: one extra line of text and everything shifts. Flexbox and Grid were designed to remove that upkeep, and most of the errors below are ones developers keep patching by hand. Here are the usual suspects, each with the modern replacement.
1. Pinning containers to a fixed height
A card set to height: 300px looks tidy in a design file. In a browser it becomes a trap. A longer product name on a narrow screen pushes content past the bottom edge, where it either clips or spills into the next section. Translated text has the same effect, because German and Finnish are often longer than English.
Let content set the height, and use min-height if you need a floor.
Equal-height columns need no measurement at all. Flex items stretch to the tallest sibling by default, so display: flex on the row matches the cards for free.
Full-height heroes have their own version of this. height: 100vh can sit under a mobile address bar and force a scrollbar. Reach for the dynamic viewport units instead — 100svh or 100dvh — with a plain fallback for older browsers.
2. Clearing floats to build columns
Floats exist so text can wrap around an image. Borrowing them for page columns meant inventing clearfixes, overflow: hidden on the parent and clear: both pseudo-elements, all of which broke the moment one column grew taller than another.
For anything arranged in one direction — a row of buttons, a sidebar beside main content — put display: flex on the parent. The children become flex items, the parent's height accounts for all of them and nothing needs clearing.
When items must line up in rows and columns at once, use Grid. Keep floats for the job they were designed for: an image with prose flowing around it.
If you find yourself adding a clearfix, ask whether Flexbox or Grid would do the job without the extra markup.
3. Faking gutters with margins and percentages
The classic three-column row — width: 32%; margin-right: 2%; plus a :last-child rule to strip the final margin — breaks as soon as a fourth item arrives or a column wraps onto its own line, trailing a stray gap behind it.
Flexbox and Grid both accept gap, which adds space only between items. No :last-child rule, no percentage arithmetic, and it keeps working when rows wrap, which margin-based gutters do not.
On the parent: display: flex; gap: 1rem; That is the whole gutter.
Prefer rem over pixels for spacing. It follows the user's text size, so someone who has increased their default font gets a layout that scales with it.
4. Centring with absolute positioning and transforms
The old recipe — position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) — does centre an element, but it lifts it out of normal flow. The parent collapses unless you give it a height, and you are back to fixed values.
With Flexbox, put three declarations on the parent and nothing on the child: display: flex; justify-content: center; align-items: center;
With Grid it is shorter still. place-items: center handles both axes and turns the container into a single cell.
Choose based on what surrounds it. If the parent is already a flex row, centre with align-items and justify-content. If you only need one item centred in a box, Grid's one-liner reads better.
5. Aligning vertically with line-height or table-cell
Setting line-height equal to the element's height centres one line of text, and only one. When the label wraps, the second line escapes the box. display: table-cell with vertical-align: middle works, but drags table layout behaviour into a component that has nothing to do with tables.
Inside a flex container, align-items: center centres on the cross axis and keeps behaving as content grows. For a button label or an icon beside a caption, display: grid; place-items: center; does the same job in one line. Both cope with multi-line content.
6. Letting flex items refuse to shrink
A flex row holding a long unbroken string — a URL, a file path, an identifier — will widen past its parent and give the whole page a horizontal scrollbar. A flex item's automatic minimum size is based on its content, so it will not shrink below that width.
Fix it with min-width: 0 on the item that needs to give way. Once the floor is lifted, overflow: hidden, text-overflow: ellipsis and white-space: nowrap can do their work.
Everyday text with spaces is fine. Tables, preformatted blocks, embedded frames and long keys are the usual culprits. In Grid, minmax(0, 1fr) in your column definition prevents the same blowout by allowing the track to shrink below its content's minimum size.
7. Assuming flex-basis and width are interchangeable
When you set width: 200px on a flex item, it might not stay 200px. Flexbox uses flex-basis as the initial main size, and if you haven't set it, it falls back to the width (or content size). The shorthand flex: 1 sets flex-basis: 0%, so any width you declared is ignored in favor of distributing free space.
If you want a starting size that can grow or shrink, use flex: 1 1 200px or explicitly set flex-basis: 200px. Remember: flex-grow and flex-shrink control how items expand and contract, while flex-basis defines the base. Mixing up these properties is why some items refuse to shrink or grow as expected.
8. Forgetting that flex rows don't wrap by default
A flex container defaults to flex-wrap: nowrap, meaning all items are forced onto a single line. If the combined width exceeds the container, items shrink (or overflow if they can't). For a tag cloud, a toolbar that should break on narrow screens, or a set of cards, you almost always want flex-wrap: wrap.
Add it to the parent: display: flex; flex-wrap: wrap; gap: 1rem; Now items wrap onto new lines as needed, and the gap keeps spacing consistent. Without wrapping, you'll see a horizontal scrollbar or squeezed items that lose their readability.
Grid doesn't have this problem because it places items into a grid and creates new rows automatically, but Flexbox requires an explicit opt-in to wrap.
Flexbox and Grid are not just replacements for old hacks; they are declarative layout systems that handle content changes gracefully. The next time you reach for a fixed height or a clearfix, consider whether a few lines of modern CSS would let the browser do the work instead.


