Responsive Patterns
Mobile-First Breakpoints
/* Define breakpoints as custom media (PostCSS or native) */
:root {
--bp-sm: 640px;
--bp-md: 768px;
--bp-lg: 1024px;
--bp-xl: 1280px;
}
/* Mobile first — add complexity upward */
.card { flex-direction: column; }
@media (min-width: 768px) { .card { flex-direction: row; } }
/* Avoid max-width overrides — they lead to specificity wars */
Fluid Typography with clamp()
/* clamp(min, preferred, max) — no breakpoints needed */
:root {
--text-base: clamp(1rem, 0.9rem + 0.4vw, 1.125rem);
--text-xl: clamp(1.25rem, 1rem + 1vw, 2rem);
--text-hero: clamp(2rem, 1rem + 5vw, 5rem);
--space-section: clamp(3rem, 2rem + 5vw, 8rem);
}
Container Queries (Preferred Over Media Queries for Components)
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Style based on available space, not viewport */
@container card (min-width: 500px) {
.card { display: grid; grid-template-columns: 200px 1fr; }
}
@container card (max-width: 300px) {
.card__meta { display: none; }
}
Viewport Units
/* dvh accounts for mobile browser chrome */
.hero { min-height: 100dvh; }
.modal { max-height: 90dvh; overflow-y: auto; }
/* svh = small viewport height (most restrictive) */
/* lvh = large viewport height (most generous) */
/* Fluid spacing without media queries */
.section { padding-block: clamp(3rem, 5dvh, 8rem); }
Intrinsic Responsive Grid
/* Auto-fill columns — no breakpoints needed */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
gap: clamp(1rem, 2vw, 2rem);
}
Responsive Images
<img
srcset="img-400.webp 400w, img-800.webp 800w, img-1200.webp 1200w"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw"
src="img-800.webp"
alt="" width="800" height="600" loading="lazy">
Aspect Ratio
/* Maintain ratio without padding-top hack */
.video-embed {
aspect-ratio: 16 / 9;
width: 100%;
}
.avatar {
aspect-ratio: 1;
width: clamp(40px, 8vw, 80px);
border-radius: 50%;
}
Touch Targets
/* WCAG 2.5.5: touch targets >= 44x44px */
.icon-button {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
Responsive Table
/* Scroll on small screens */
.table-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
table { min-width: 600px; }
/* Or stack with data attributes */
@media (max-width: 640px) {
thead { display: none; }
tr { display: block; border: 1px solid var(--color-border); margin-block: 1rem; }
td { display: flex; justify-content: space-between; }
td::before { content: attr(data-label); font-weight: bold; }
}