Skip to main content
Back to module
Accessible & Responsive Interfaces · Responsive Design

Responsive layout patterns

Reading30mLesson 2 of 3 in this module

Build a card grid, wrapping navigation and a container query that reflow at any width.

Why this matters

A layout that only works at the width it was designed for breaks for most visitors: phones, tablets, split-screen windows and anyone zoomed to 400 percent. WCAG 1.4.10 Reflow (AA) requires that content works at 320 CSS px wide without horizontal scrolling (except for things like maps and data tables that genuinely need two dimensions). Modern CSS can do most of this with no media queries at all.

Mobile-first, then let content decide

Start with a single column, which works on any screen, and add complexity only where there is room. Instead of guessing device widths ("iPhone", "iPad"), let the content decide: add a breakpoint when the layout starts to look wrong. Write breakpoints in em or rem so they also respond to zoom:

.page { display: grid; gap: 1rem; }
@media (min-width: 48em) {
  .page { grid-template-columns: 16rem 1fr; }  /* sidebar appears when there is room */
}

Pattern 1: the auto-fit card grid

This one line creates as many columns as fit, each at least 15rem wide, sharing extra space equally:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: 1rem;
}

Read it inside out:

  • minmax(15rem, 1fr): each column is at least 15rem and at most an equal share.
  • min(15rem, 100%): on a screen narrower than 15rem (or at high zoom), the minimum becomes 100 percent instead, so the card never overflows. Without this guard, a 320 px screen with a 15rem (240 px) minimum is fine, but larger minimums cause sideways scrolling.
  • auto-fit vs auto-fill: both create as many tracks as fit. With few items, auto-fit collapses empty tracks so items stretch; auto-fill keeps the empty tracks.

No media query is needed: the browser reflows from one column to four as space allows. Kevin Powell and others call these "intrinsic" or "breakpoint-free" layouts.

Pattern 2: wrapping rows with Flexbox

For a row of navigation links, tags or buttons:

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  list-style: none;
  padding: 0;
}

flex-wrap: wrap lets items move to a new line instead of overflowing. gap spaces them evenly without margin hacks.

Pattern 3: the sidebar that drops below

.with-sidebar { display: flex; flex-wrap: wrap; gap: 1rem; }
.with-sidebar > aside { flex: 1 1 15rem; }
.with-sidebar > main  { flex: 999 1 30rem; }

The main area grows much faster, and when there is not room for 15rem plus 30rem the sidebar wraps underneath. Again, no breakpoint.

Pattern 4: container queries

Media queries ask "how wide is the window?". A card in a narrow sidebar and the same card in a wide main column need different layouts, even though the window is the same. Container queries ask "how wide is my container?" and are supported in all current browsers:

.card-wrap { container-type: inline-size; }

.card { display: grid; gap: 0.5rem; }
@container (min-width: 28rem) {
  .card { grid-template-columns: 8rem 1fr; }  /* image beside text when the card is wide */
}

container-type: inline-size makes the element a query container for its width. Components that adapt to their own space are much easier to reuse in a design system.

Worked example: fixing a fixed-width card row

The broken version:

.cards { display: flex; }
.card  { width: 300px; flex-shrink: 0; }

Four cards need 1200 px. On a phone, three of them hang off the right edge, forcing sideways scrolling and failing Reflow. The fix replaces both rules with the auto-fit grid above and removes the fixed width. Test by dragging the window narrower, then by zooming to 400 percent at 1280 px wide: the cards should stack into one column with no horizontal scrollbar.

Accessibility and layout

  • Keep DOM order meaningful. Grid placement and order can move items visually without changing the reading and tab order. Screen reader and keyboard users get the DOM order.
  • Avoid fixed heights. Content grows when text is zoomed or spaced (1.4.12); let height be automatic.
  • Watch sticky elements. A sticky header that is fine at 100 percent can cover half the screen at 400 percent zoom. Consider removing stickiness on short viewports with @media (max-height: 30em).

Common mistakes

  • Breakpoints in px tied to specific devices.
  • width in pixels on flexible items.
  • Forgetting the min(…, 100%) guard, which causes overflow on narrow screens.
  • Using transition-all or animating width to "smooth" reflow; animate only transform and opacity.
  • Testing only at a few preset device sizes in DevTools instead of dragging through every width.

Quick recap

  • Start mobile-first; let content choose breakpoints, written in em/rem.
  • repeat(auto-fit, minmax(min(15rem, 100%), 1fr)) gives a reflowing grid.
  • flex-wrap: wrap and gap for rows; the flex sidebar trick for two columns.
  • Container queries let components respond to their own width.
  • Check against WCAG Understanding 1.4.10 Reflow.

Try it

Open the Do tab and turn a fixed card row into a layout that reflows.

Also in this lesson: