Responsive CSS Patterns You Can Copy

2026-03-29SPUNK13spunk.bet

A card grid with no media queries at all

This is the single highest-value pattern in modern CSS. The grid decides its own column count from the available width, so it works inside a full-width page, a narrow sidebar, or a modal without you writing a breakpoint.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

Two gotchas. auto-fit collapses empty tracks so three cards stretch to fill the row; auto-fill keeps the empty tracks and leaves a gap on the right. Pick deliberately. And on a container narrower than 280px the item overflows, because minmax enforces that minimum. If that is possible, use minmax(min(280px, 100%), 1fr).

Fluid type that stops growing

:root {
  --step-0: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --step-1: clamp(1.25rem, 1.05rem + 1vw, 1.75rem);
  --step-2: clamp(1.6rem, 1.2rem + 2vw, 2.75rem);
}
body { font-size: var(--step-0); }
h2   { font-size: var(--step-1); }
h1   { font-size: var(--step-2); }

The rem part of the middle value is what keeps this accessible. A pure clamp(1rem, 2vw, 1.25rem) ignores the user's browser font size at most viewport widths, so someone who set 24px default text still gets your 16px. Mixing a rem term with the vw term means zoom and user preferences still move the result.

Container queries for components that travel

Media queries ask how wide the window is. That is the wrong question for a card that appears in a three-column grid on one page and a narrow rail on another. Container queries ask how wide the card's own parent is.

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

.card { display: grid; gap: 1rem; }

@container (min-width: 400px) {
  .card {
    grid-template-columns: 140px 1fr;
    align-items: start;
  }
}

Note that container-type: inline-size goes on the wrapper, not on the element you are styling, because an element cannot query itself. Naming it with container-name is worth doing once you have nested containers. Inside a query you can also use cqw units, which are percentages of the container rather than the viewport.

A sidebar that wraps by itself

Flexbox handles the classic content-plus-sidebar layout without a breakpoint. The sidebar keeps a fixed ideal width, the content claims a minimum percentage, and when they no longer both fit, the content's flex-basis forces a wrap to one column.

.with-sidebar { display: flex; flex-wrap: wrap; gap: 2rem; }

.with-sidebar > .side { flex: 1 1 18rem; }

.with-sidebar > .main {
  flex: 999 1 60%;   /* refuses to sit next to the sidebar below 60% */
  min-width: 0;      /* lets long words and pre blocks shrink */
}

The min-width: 0 line is not optional. Flex items default to min-width: auto, which is why a wide table or a code block blows the layout out and gives you a horizontally scrolling page.

Media boxes, measure and viewport height

.media { aspect-ratio: 16 / 9; }
.media > img, .media > video, .media > iframe {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

.content { width: min(90vw, 70ch); margin-inline: auto; }

.hero { min-height: 100svh; }   /* not 100vh */

aspect-ratio reserves the space before the image loads, which removes the layout shift you would otherwise get. width: min(90vw, 70ch) gives one rule that caps line length around 70 characters for readability and still leaves gutters on a phone. And 100vh on mobile measures the viewport as if the browser chrome were hidden, so a full-height hero gets clipped by the address bar; svh, lvh and dvh address the small, large and dynamic cases.

Motion preferences and how many breakpoints you need

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

Near-zero rather than none is intentional: animationend and transitionend handlers still fire, so JavaScript that waits for them does not hang.

On breakpoints: two or three is usually the right number, and none of them should be named after a device. Resize the browser slowly and add a breakpoint at the width where the layout genuinely looks wrong, which is typically somewhere around 40rem and 64rem. Write them in rem, because a media query in px ignores the user's font size and pushes zoomed-in users into a layout meant for a phone. Every pattern above removes a breakpoint you would otherwise have to maintain.

Keep Going

Free tools, guides, and resources across the SPUNK13 network.

Visit spunk.bet400+ Free Tools
Dev ToolsCasinoMemesAstrologyScam DBBacklinksEbooks