CSS Layout Patterns That Actually Work for Small Business Sites (2026)

For small business sites, use CSS Grid for page structure and Flexbox for components. Grid handles rows and columns together, Flexbox handles a single row or stack. I use minmax(0, 1fr) to stop long strings causing horizontal scroll, and 100dvh so mobile browser chrome doesn't break full-height layouts.
Part of the complete web design guide.
On this page
- Start with Grid for page structure, Flexbox for components
- Component-level layout stays in Flexbox
- Container queries replaced a lot of my media queries
- Fluid type and spacing without a hundred breakpoints
- The patterns I’d avoid in 2026
- Accessibility and layout are the same conversation
- When to hand it off
- FAQ
- Do I still need media queries in 2026?
- Is Grid slower than Flexbox?
- What’s the minimum I need to know to fix a broken layout?
Most small business sites don’t need clever CSS. They need layouts that hold up when the content changes, when the client adds a three-word service name, and when someone opens the site on a five-year-old Android phone. I’ve rebuilt enough of them to know which patterns survive and which ones create work later.
Here’s what I actually reach for in 2026, and why.
Start with Grid for page structure, Flexbox for components
This is the rule I come back to constantly. CSS Grid handles two-dimensional layout (rows and columns at the same time). Flexbox handles one dimension (a row of buttons, a stack of cards). Mixing them up is where most messy CSS comes from.
Page-level structure is almost always Grid:
.site {
display: grid;
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto 1fr auto;
min-height: 100dvh;
}
.site-header { grid-row: 1; }
.site-main { grid-row: 2; }
.site-footer { grid-row: 3; }
That minmax(0, 1fr) matters. Plain 1fr can blow out when a long unbroken string (a URL, an email) lands in a column, because the track refuses to shrink below its content’s min-content size. Wrapping it in minmax(0, 1fr) lets it shrink. I’ve fixed more horizontal-scroll bugs with that one change than any other.
And 100dvh instead of 100vh because mobile browser chrome (the address bar) collapses and expands. vh doesn’t account for it. dvh does.
Component-level layout stays in Flexbox
.card-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
align-items: center;
}
Buttons, nav bars, card footers, form rows. Flexbox with gap is cleaner than margin hacks and it doesn’t care how many items you drop in.
Container queries replaced a lot of my media queries
This is the biggest practical change since Grid landed. Container queries let a component respond to the size of its parent, not the viewport. That means the same card works in a wide sidebar and a narrow three-column grid without any special-casing.
.card-wrap {
container-type: inline-size;
container-name: card;
}
.card {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
@container card (min-width: 28rem) {
.card {
grid-template-columns: 8rem 1fr;
align-items: start;
}
}
Browser support for container queries has been solid across all current engines for a while now. If you’re still writing five breakpoint overrides for one card, this is the fix.
Note container-type: inline-size only measures width, which is what you want most of the time. Use size only if you genuinely need height too, since it can cause layout loops if you’re not careful.
Fluid type and spacing without a hundred breakpoints
Clamp-based sizing means fewer media queries and less code to maintain. One line handles the whole range:
:root {
--step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--step-2: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
--space-m: clamp(1rem, 0.8rem + 1vw, 2rem);
}
h2 { font-size: var(--step-2); }
section { padding-block: var(--space-m); }
The middle value is a formula, not a guess. 0.95rem + 0.25vw means “start near 1rem and grow slightly with viewport width.” The clamp bounds stop it from getting silly on a 4K monitor or a 320px phone. This is basically what utopia.fyi generates, and I’d rather paste three variables than maintain twenty breakpoints.
The patterns I’d avoid in 2026
- Float-based layout. If you inherit a codebase still using
float: leftfor columns, that’s a rewrite, not a patch. Floats are for text wrapping around images now, nothing else. - Absolute positioning for main structure. It works until the content changes length. Then it breaks, and it breaks in ways that only show up on the client’s phone.
- JavaScript-driven layout. Measuring element heights in JS to set a grid is fragile. ResizeObserver, fonts loading late, images without dimensions. Grid and container queries handle this declaratively.
- Fixed pixel widths on containers. A 960px fixed wrapper was fine in 2010. It’s a liability on a 360px phone and a waste on a 1440px laptop.
Accessibility and layout are the same conversation
Layout choices decide tab order. If you reorder things visually with Grid but leave the DOM in a different order, keyboard users get a confusing ride. Keep source order matching what people see. If you can’t, that’s a signal the design needs rethinking, not a CSS trick.
Same with overflow and zoom. If your layout scrolls horizontally at 200% zoom, you’ve failed a WCAG requirement. Grid with minmax(0, 1fr) and fluid type mostly prevents this for free.
When to hand it off
I do this work for small businesses around here, and honestly, most of them don’t need a custom layout system. They need a site that loads fast, doesn’t break when they add a new service, and looks right on the phones their customers actually use. If you’re weighing whether to patch an old theme or start clean, that’s usually a Long Island web design conversation more than a CSS one. The code is the easy part. Deciding what the site needs to do is the part worth getting right first.
FAQ
Do I still need media queries in 2026?
Yes, but far fewer. Use them for genuine page-level shifts (nav collapsing to a hamburger, a sidebar moving below the content). Use container queries for anything component-shaped.
Is Grid slower than Flexbox?
No. Performance differences are negligible in practice. Pick based on whether you’re laying out one dimension (Flexbox) or two (Grid).
What’s the minimum I need to know to fix a broken layout?
Understand display: grid, grid-template-columns, gap, and minmax(0, 1fr). That covers the majority of real-world layout bugs I run into.


