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).
: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.
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.
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 { 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.
@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.
Free tools, guides, and resources across the SPUNK13 network.
Visit spunk.bet400+ Free Tools