CSS Responsive Design and Media Queries
1. Media Query Syntax (@media) and Features
| Component | Syntax | Description | Example |
|---|---|---|---|
| @media | @media type and (feature) |
Apply styles conditionally based on device characteristics | @media screen and (min-width: 768px) |
| Media Types | all | screen | print | speech |
Target specific device types | @media print { ... } |
| Logical Operators | and | or | not | only |
Combine multiple media features | (min-width: 768px) and (max-width: 1024px) |
| Width Queries | min-width | max-width | width |
Query viewport or container width | (min-width: 768px) |
| Height Queries | min-height | max-height | height |
Query viewport or container height | (min-height: 600px) |
| Orientation | portrait | landscape |
Detect device orientation | (orientation: landscape) |
| Aspect Ratio | aspect-ratio: width/height |
Query viewport aspect ratio | (aspect-ratio: 16/9) |
| Resolution | resolution: value |
Query pixel density (dpi, dpcm, dppx) | (resolution: 2dppx) for Retina |
| Display Mode | display-mode: value |
Detect PWA display mode | (display-mode: standalone) |
| Pointer | pointer: none | coarse | fine |
Primary input mechanism precision | (pointer: coarse) for touch |
| Hover | hover: none | hover |
Can primary input hover over elements | (hover: hover) for mouse |
| Any-pointer | any-pointer: none | coarse | fine |
Any available input mechanism | (any-pointer: fine) |
| Any-hover | any-hover: none | hover |
Any available input can hover | (any-hover: hover) |
Example: Basic media query patterns
/* Mobile-first approach (min-width) */
.container {
width: 100%;
}
@media (min-width: 768px) {
.container {
width: 750px;
}
}
@media (min-width: 1024px) {
.container {
width: 980px;
}
}
@media (min-width: 1280px) {
.container {
width: 1200px;
}
}
/* Desktop-first approach (max-width) */
.nav {
display: flex;
}
@media (max-width: 1023px) {
.nav {
display: none;
}
}
/* Range queries (Level 4 syntax) */
@media (768px <= width <= 1024px) {
.tablet-only {
display: block;
}
}
/* Multiple conditions */
@media screen and (min-width: 768px) and (orientation: landscape) {
.landscape-tablet {
grid-template-columns: repeat(3, 1fr);
}
}
/* Print styles */
@media print {
.no-print {
display: none;
}
body {
font-size: 12pt;
color: black;
background: white;
}
}
Example: User interaction and device queries
/* Touch device detection */
@media (hover: none) and (pointer: coarse) {
/* Touch-only device */
button {
min-height: 44px; /* Larger touch targets */
min-width: 44px;
}
}
/* Mouse/trackpad device */
@media (hover: hover) and (pointer: fine) {
.interactive:hover {
background: #f0f0f0;
}
}
/* Hybrid device (touch + mouse) */
@media (any-hover: hover) {
.tooltip {
display: none;
}
.element:hover .tooltip {
display: block;
}
}
/* High-resolution displays (Retina) */
@media (resolution: 2dppx), (resolution: 192dpi) {
.logo {
background-image: url('logo@2x.png');
background-size: 100px 50px;
}
}
/* PWA standalone mode */
@media (display-mode: standalone) {
.install-prompt {
display: none;
}
.app-header {
padding-top: env(safe-area-inset-top);
}
}
/* Landscape orientation */
@media (orientation: landscape) {
.video-player {
height: 100vh;
}
}
/* Specific aspect ratios */
@media (aspect-ratio: 16/9) {
.widescreen-layout {
display: grid;
grid-template-columns: 2fr 1fr;
}
}
Note: Use
(hover: hover) to distinguish devices with mouse from touch devices. Use
any-hover for hybrid devices. Modern Level 4 range syntax: (width >= 768px) is
cleaner than (min-width: 768px).
2. Responsive Units (vw, vh, rem, em) and Viewport
| Unit | Full Name | Description | Use Case |
|---|---|---|---|
| vw | Viewport Width | 1% of viewport width | Full-width elements, responsive font sizes |
| vh | Viewport Height | 1% of viewport height | Full-height sections, hero images |
| vmin | Viewport Minimum | 1% of smaller viewport dimension | Square elements that fit any orientation |
| vmax | Viewport Maximum | 1% of larger viewport dimension | Background images, diagonal layouts |
| svh NEW | Small Viewport Height | Height when UI is expanded (mobile) | Fixed mobile headers, reliable 100% height |
| lvh NEW | Large Viewport Height | Height when UI is retracted | Full-screen experiences |
| dvh NEW | Dynamic Viewport Height | Adjusts as browser UI shows/hides | Smooth mobile experiences |
| vi, vb | Viewport Inline/Block | Writing mode aware viewport units | Internationalized layouts |
| % | Percentage | Relative to parent element | Fluid layouts, responsive sizing |
| rem | Root Em | Relative to root font-size (html) | Consistent spacing, scalable layouts |
| em | Em | Relative to parent font-size | Component-scoped scaling |
| ch | Character | Width of "0" character | Optimal reading line length (45-75ch) |
| ex | X-height | Height of lowercase "x" | Vertical rhythm, icon sizing |
Example: Viewport units for responsive layouts
/* Full-viewport hero section */
.hero {
height: 100vh; /* May have issues on mobile */
height: 100dvh; /* Better: adjusts with mobile browser UI */
display: flex;
align-items: center;
justify-content: center;
}
/* Mobile-safe full height */
.mobile-full-height {
min-height: 100svh; /* Smallest viewport (UI visible) */
min-height: 100dvh; /* Fallback for dynamic */
}
/* Fluid typography with viewport units */
.responsive-text {
font-size: calc(16px + 1vw); /* Grows with viewport */
/* Better: use clamp() for min/max bounds */
}
/* Square element regardless of orientation */
.square {
width: 50vmin;
height: 50vmin;
}
/* Responsive spacing with rem */
:root {
font-size: 16px;
}
@media (min-width: 768px) {
:root {
font-size: 18px; /* All rem values scale up */
}
}
.section {
padding: 2rem; /* 32px mobile, 36px tablet+ */
margin-bottom: 3rem;
}
/* Optimal reading width */
.article {
max-width: 65ch; /* ~65 characters per line */
margin: 0 auto;
}
/* Percentage-based fluid grid */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2%; /* Scales with container */
}
Example: Small/Large/Dynamic viewport units (mobile)
/* Problem: 100vh on mobile includes browser UI space */
.old-full-height {
height: 100vh; /* May extend below visible area */
}
/* Solution 1: Small viewport (UI always visible) */
.safe-full-height {
height: 100svh; /* Accounts for mobile browser chrome */
}
/* Solution 2: Large viewport (UI hidden) */
.expanded-full-height {
height: 100lvh; /* Maximum available space */
}
/* Solution 3: Dynamic (recommended) */
.adaptive-full-height {
height: 100vh; /* Fallback */
height: 100dvh; /* Smoothly adjusts as UI shows/hides */
}
/* Width equivalents */
.full-width {
width: 100vw; /* Standard */
width: 100dvw; /* Dynamic (for horizontal scrolling scenarios) */
}
/* Practical example: Mobile modal */
.modal-overlay {
position: fixed;
inset: 0;
height: 100dvh; /* Covers visible viewport */
width: 100dvw;
background: rgba(0, 0, 0, 0.5);
}
.modal-content {
max-height: 90dvh; /* Leave space for gestures */
overflow-y: auto;
}
Warning:
100vh on mobile includes browser UI, causing overflow. Use
100dvh for dynamic adjustment or 100svh for consistently safe height. Browser support:
Chrome 108+, Safari 15.4+.
3. Container Queries Implementation NEW
| Property | Syntax | Description | Example |
|---|---|---|---|
| container-type | size | inline-size | normal |
Define element as query container | container-type: inline-size; |
| container-name | name |
Name container for targeted queries | container-name: sidebar; |
| container | name / type |
Shorthand for name and type | container: card / inline-size; |
| @container | @container (condition) { } |
Query container dimensions | @container (min-width: 400px) |
| cqw | Container Query Width | 1% of container's width | font-size: 5cqw; |
| cqh | Container Query Height | 1% of container's height | padding: 2cqh; |
| cqi | Container Query Inline | 1% of inline axis (width in LTR) | margin: 3cqi; |
| cqb | Container Query Block | 1% of block axis (height in LTR) | gap: 2cqb; |
| cqmin, cqmax | Container Query Min/Max | 1% of smaller/larger dimension | width: 50cqmin; |
Example: Container queries for component-based responsive design
/* Define container */
.card-grid {
container-type: inline-size;
container-name: card-container;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
/* Query container, not viewport */
.card {
padding: 1rem;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
gap: 1rem;
}
.card-image {
height: 150px;
}
}
@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr;
}
.card-title {
font-size: 1.5rem;
}
}
/* Named container queries */
.sidebar {
container: sidebar / inline-size;
}
@container sidebar (min-width: 300px) {
.sidebar-widget {
display: block;
}
}
@container sidebar (min-width: 500px) {
.sidebar-widget {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
Example: Container query units for intrinsic responsive design
/* Responsive typography with container units */
.container {
container-type: inline-size;
}
.headline {
font-size: clamp(1rem, 5cqi, 3rem);
/* Scales with container, not viewport */
}
/* Container-relative spacing */
.card {
padding: 3cqi 4cqi;
gap: 2cqi;
}
/* Grid with container units */
@container (min-width: 500px) {
.grid {
display: grid;
grid-template-columns: 30cqi 1fr;
gap: 3cqi;
}
}
/* Aspect ratio with container units */
.media {
width: 100cqi;
height: 56cqi; /* 16:9 aspect ratio based on container */
}
/* Fluid icon sizing */
.icon {
width: 8cqi;
height: 8cqi;
max-width: 48px; /* Cap size */
}
/* Container-relative transforms */
.floating-element {
transform: translateX(10cqi);
}
/* Responsive grid tracks */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(25cqi, 1fr));
gap: 2cqi;
}
Note: Container queries enable true component-based responsive
design. Components adapt to their container size, not viewport. Use
inline-size for
width-only queries (most common). Browser support: Chrome 105+, Safari 16+, Firefox 110+.
4. Responsive Typography (clamp, min, max)
| Function | Syntax | Description | Use Case |
|---|---|---|---|
| clamp() | clamp(min, preferred, max) |
Value between min and max bounds | Fluid typography that scales with viewport |
| min() | min(value1, value2, ...) |
Smallest of provided values | Ensure element doesn't exceed size |
| max() | max(value1, value2, ...) |
Largest of provided values | Ensure minimum size is maintained |
| calc() | calc(expression) |
Mathematical calculations | Combine units, create fluid scales |
Example: Fluid typography with clamp()
/* Fluid font-size that scales between bounds */
h1 {
font-size: clamp(2rem, 5vw, 4rem);
/* Min: 2rem (32px)
Preferred: 5vw (grows with viewport)
Max: 4rem (64px) */
}
h2 {
font-size: clamp(1.5rem, 3vw + 1rem, 3rem);
}
p {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
}
/* Fluid spacing */
.section {
padding: clamp(1rem, 5vw, 4rem) clamp(1rem, 5vw, 2rem);
margin-bottom: clamp(2rem, 8vh, 6rem);
}
/* Fluid line-height */
.article {
line-height: clamp(1.4, 1.2 + 0.5vw, 1.8);
}
/* Type scale with clamp() */
:root {
--fs-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--fs-sm: clamp(0.875rem, 0.8rem + 0.4vw, 1rem);
--fs-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--fs-lg: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
--fs-xl: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
--fs-2xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
.text-xs { font-size: var(--fs-xs); }
.text-sm { font-size: var(--fs-sm); }
.text-base { font-size: var(--fs-base); }
.text-lg { font-size: var(--fs-lg); }
.text-xl { font-size: var(--fs-xl); }
.text-2xl { font-size: var(--fs-2xl); }
Example: Responsive layout with min/max/clamp
/* Fluid container width */
.container {
width: min(100% - 2rem, 1200px);
/* Never exceeds 1200px, has 1rem padding on mobile */
margin: 0 auto;
}
/* Responsive grid columns */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
/* Columns min 250px but won't break on narrow screens */
gap: clamp(1rem, 3vw, 2rem);
}
/* Fluid gap sizing */
.flex-container {
display: flex;
gap: clamp(0.5rem, 2vw, 2rem);
}
/* Responsive padding without media queries */
.card {
padding: clamp(1rem, 4vw, 3rem);
}
/* Optimal reading width */
.article {
max-width: min(65ch, 100% - 4rem);
/* Max 65 characters but leaves margin on narrow screens */
}
/* Fluid border-radius */
.button {
border-radius: clamp(4px, 0.5vw, 8px);
}
/* Height constraints */
.hero {
min-height: max(400px, 50vh);
/* At least 400px, but grows on tall screens */
}
/* Aspect ratio with bounds */
.video-container {
height: clamp(300px, 56.25vw, 720px);
/* Maintains ~16:9 ratio with min/max */
}
Example: Advanced fluid typography calculation
/* Calculate fluid typography slope */
/*
Formula: clamp(minSize, minSize + (maxSize - minSize) * ((100vw - minVw) / (maxVw - minVw)), maxSize)
Example calculation for h1:
- Viewport range: 320px to 1200px
- Font size range: 24px to 64px
*/
h1 {
/* Simple version */
font-size: clamp(1.5rem, 2vw + 1rem, 4rem);
/* Precise calculation */
font-size: clamp(
1.5rem,
1.5rem + (4 - 1.5) * ((100vw - 20rem) / (75 - 20)),
4rem
);
}
/* Fluid type scale generator */
:root {
/* Base settings */
--fluid-min-width: 320;
--fluid-max-width: 1200;
--fluid-min-size: 16;
--fluid-max-size: 20;
/* Calculate slope */
--fluid-min-ratio: 1.2;
--fluid-max-ratio: 1.333;
/* Apply to scale */
--step-0: clamp(
calc(var(--fluid-min-size) * 1px),
calc((var(--fluid-min-size) * 1px) + (var(--fluid-max-size) - var(--fluid-min-size)) * ((100vw - (var(--fluid-min-width) * 1px)) / (var(--fluid-max-width) - var(--fluid-min-width)))),
calc(var(--fluid-max-size) * 1px)
);
}
/* Container query-based fluid typography */
.card-container {
container-type: inline-size;
}
.card-title {
font-size: clamp(1rem, 5cqi, 2.5rem);
/* Scales with container, not viewport */
}
Note:
clamp() eliminates most responsive typography media queries. Formula:
clamp(min, base + scaleFactor, max). Use viewport units (vw, vh) or container units (cqi, cqb) for
fluid scaling. Tools: utopia.fyi for fluid type scale
generation.
5. Responsive Images and Picture Element
| Feature | Syntax | Description | Use Case |
|---|---|---|---|
| srcset | srcset="url 1x, url 2x" |
Multiple resolution image sources | Serve higher resolution for Retina displays |
| sizes | sizes="(query) width" |
Define image display width at breakpoints | Let browser choose optimal image size |
| picture | <picture><source><img> |
Art direction for different layouts | Different crops/images per breakpoint |
| source type | <source type="image/webp"> |
Serve modern image formats | WebP, AVIF with fallback to JPEG |
| loading | loading="lazy" |
Native lazy loading | Defer offscreen images, improve performance |
| decoding | decoding="async" |
Asynchronous image decoding | Non-blocking image loading |
| fetchpriority | fetchpriority="high" |
Hint browser about image priority | Prioritize hero images, defer others |
| aspect-ratio | aspect-ratio: 16/9 |
Reserve space before image loads | Prevent layout shift (CLS) |
| object-fit | cover | contain | fill |
Control image sizing in container | Maintain aspect ratio while fitting |
| object-position | top | center | 20% 40% |
Position image within container | Focus on specific area when cropped |
Example: Responsive images with srcset and sizes
<!-- Resolution switching (1x, 2x, 3x) -->
<img
src="image-1x.jpg"
srcset="image-1x.jpg 1x,
image-2x.jpg 2x,
image-3x.jpg 3x"
alt="Description"
/>
<!-- Width-based selection -->
<img
src="image-800w.jpg"
srcset="image-400w.jpg 400w,
image-800w.jpg 800w,
image-1200w.jpg 1200w,
image-1600w.jpg 1600w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
alt="Description"
/>
<!-- Browser selects best image based on:
- Screen width and DPR
- sizes attribute hints -->
<!-- Complex sizes attribute -->
<img
src="fallback.jpg"
srcset="small.jpg 400w,
medium.jpg 800w,
large.jpg 1200w"
sizes="(max-width: 400px) 100vw,
(max-width: 800px) 80vw,
(max-width: 1200px) 60vw,
800px"
alt="Responsive image"
loading="lazy"
decoding="async"
/>
Example: Picture element for art direction
<!-- Different images for different layouts -->
<picture>
<!-- Mobile: portrait crop -->
<source
media="(max-width: 600px)"
srcset="portrait-400w.jpg 400w,
portrait-800w.jpg 800w"
sizes="100vw"
/>
<!-- Tablet: square crop -->
<source
media="(max-width: 1200px)"
srcset="square-600w.jpg 600w,
square-1200w.jpg 1200w"
sizes="50vw"
/>
<!-- Desktop: landscape crop -->
<source
media="(min-width: 1201px)"
srcset="landscape-800w.jpg 800w,
landscape-1600w.jpg 1600w"
sizes="800px"
/>
<!-- Fallback -->
<img src="landscape-800w.jpg" alt="Hero image" />
</picture>
<!-- Modern format with fallback -->
<picture>
<!-- AVIF (best compression) -->
<source
type="image/avif"
srcset="image.avif"
/>
<!-- WebP (good compression) -->
<source
type="image/webp"
srcset="image.webp"
/>
<!-- JPEG fallback -->
<img src="image.jpg" alt="Description" />
</picture>
<!-- Combine format and responsive sizing -->
<picture>
<source
type="image/avif"
srcset="image-400w.avif 400w,
image-800w.avif 800w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<source
type="image/webp"
srcset="image-400w.webp 400w,
image-800w.webp 800w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<img
src="image-800w.jpg"
srcset="image-400w.jpg 400w,
image-800w.jpg 800w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Description"
loading="lazy"
/>
</picture>
Example: CSS for responsive images
/* Responsive image container */
.image-container {
width: 100%;
aspect-ratio: 16 / 9; /* Prevent layout shift */
overflow: hidden;
background: #f0f0f0; /* Placeholder */
}
.image-container img {
width: 100%;
height: 100%;
object-fit: cover; /* Fill container, crop if needed */
object-position: center;
}
/* Art-directed positioning */
.hero-image {
object-position: top center; /* Keep top of image visible */
}
@media (max-width: 600px) {
.hero-image {
object-position: center center; /* Center on mobile */
}
}
/* Aspect ratio boxes */
.aspect-16-9 {
aspect-ratio: 16 / 9;
}
.aspect-4-3 {
aspect-ratio: 4 / 3;
}
.aspect-1-1 {
aspect-ratio: 1 / 1;
}
/* Lazy load placeholder */
img[loading="lazy"] {
background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%);
background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
}
@keyframes shimmer {
to {
background-position: -200% 0;
}
}
/* High priority hero image */
.hero img {
/* fetchpriority="high" in HTML */
content-visibility: visible;
}
/* Lazy images below fold */
.content img {
/* loading="lazy" in HTML */
content-visibility: auto;
}
/* Responsive background images */
.bg-image {
background-size: cover;
background-position: center;
}
@media (max-width: 600px) {
.bg-image {
background-image: url('mobile.jpg');
}
}
@media (min-width: 601px) and (max-width: 1200px) {
.bg-image {
background-image: url('tablet.jpg');
}
}
@media (min-width: 1201px) {
.bg-image {
background-image: url('desktop.jpg');
}
}
/* High-resolution background */
@media (resolution >= 2dppx) {
.bg-image {
background-image: url('desktop@2x.jpg');
}
}
Note: Use
srcset for resolution switching, <picture> for art
direction. Always include alt text. Set aspect-ratio to prevent CLS. Use
loading="lazy" for images below fold. Serve modern formats (AVIF, WebP) with fallbacks.
6. Mobile-first vs Desktop-first Strategies
| Strategy | Approach | Pros | Cons |
|---|---|---|---|
| Mobile-first | Base styles for mobile, use min-width to enhance for larger screens |
Progressive enhancement, better performance on mobile, simpler CSS | May require more rework for desktop-heavy sites |
| Desktop-first | Base styles for desktop, use max-width to adapt for smaller screens |
Easier for existing desktop sites, familiar workflow | Mobile devices load unnecessary desktop CSS, harder to simplify |
| Hybrid | Container queries + viewport queries | Component adapts to container, layout adapts to viewport | More complex, newer browser support |
Example: Mobile-first approach (recommended)
/* Base styles: Mobile (320px+) */
.container {
width: 100%;
padding: 1rem;
}
.nav {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.nav-link {
padding: 0.75rem;
font-size: 1rem;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
.hero {
padding: 2rem 1rem;
}
.hero h1 {
font-size: 1.75rem;
}
/* Tablet: 768px+ */
@media (min-width: 768px) {
.container {
padding: 2rem;
max-width: 720px;
margin: 0 auto;
}
.nav {
flex-direction: row;
justify-content: space-between;
}
.grid {
grid-template-columns: repeat(2, 1fr);
gap: 2rem;
}
.hero {
padding: 4rem 2rem;
}
.hero h1 {
font-size: 2.5rem;
}
}
/* Desktop: 1024px+ */
@media (min-width: 1024px) {
.container {
max-width: 960px;
}
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 3rem;
}
.hero {
padding: 6rem 3rem;
}
.hero h1 {
font-size: 3.5rem;
}
}
/* Large Desktop: 1280px+ */
@media (min-width: 1280px) {
.container {
max-width: 1200px;
}
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
Example: Desktop-first approach
/* Base styles: Desktop */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 3rem;
}
.nav {
display: flex;
justify-content: space-between;
gap: 2rem;
}
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 3rem;
}
.hero h1 {
font-size: 3.5rem;
}
/* Tablet: Below 1024px */
@media (max-width: 1023px) {
.container {
max-width: 960px;
padding: 2rem;
}
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
}
.hero h1 {
font-size: 2.5rem;
}
}
/* Mobile: Below 768px */
@media (max-width: 767px) {
.container {
padding: 1rem;
}
.nav {
flex-direction: column;
gap: 0.5rem;
}
.grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.hero h1 {
font-size: 1.75rem;
}
}
/* Small mobile: Below 480px */
@media (max-width: 479px) {
.container {
padding: 0.5rem;
}
.hero h1 {
font-size: 1.5rem;
}
}
Example: Hybrid approach with container queries
/* Global layout: Viewport-based (mobile-first) */
.page-container {
padding: 1rem;
}
@media (min-width: 768px) {
.page-container {
padding: 2rem;
}
}
@media (min-width: 1024px) {
.page-container {
display: grid;
grid-template-columns: 250px 1fr 300px;
gap: 2rem;
max-width: 1400px;
margin: 0 auto;
}
}
/* Components: Container-based (intrinsic responsive) */
.card-grid {
container-type: inline-size;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: 1rem;
}
.card {
/* Adapts to container, not viewport */
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 120px 1fr;
}
}
@container (min-width: 600px) {
.card {
grid-template-columns: 180px 1fr;
}
}
/* Typography: Fluid (no breakpoints needed) */
h1 {
font-size: clamp(1.75rem, 4vw, 3.5rem);
}
p {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
}
/* Spacing: Fluid */
.section {
padding: clamp(2rem, 5vw, 6rem) clamp(1rem, 3vw, 3rem);
}
/* Best of all approaches */
.hybrid-component {
/* Mobile-first base */
padding: 1rem;
/* Fluid scaling */
gap: clamp(0.5rem, 2vw, 2rem);
/* Container query for component */
container-type: inline-size;
}
@container (min-width: 500px) {
.hybrid-component {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
/* Viewport query for global layout */
@media (min-width: 1024px) {
.hybrid-component {
padding: 2rem;
}
}
Example: Common responsive breakpoints
/* Standard breakpoint system */
/* Extra small devices (phones) */
/* Default styles, no media query needed */
/* Small devices (large phones, 600px+) */
@media (min-width: 600px) {
/* ... */
}
/* Medium devices (tablets, 768px+) */
@media (min-width: 768px) {
/* ... */
}
/* Large devices (desktops, 1024px+) */
@media (min-width: 1024px) {
/* ... */
}
/* Extra large devices (large desktops, 1280px+) */
@media (min-width: 1280px) {
/* ... */
}
/* 2K screens (1440px+) */
@media (min-width: 1440px) {
/* ... */
}
/* 4K screens (2560px+) */
@media (min-width: 2560px) {
/* ... */
}
/* Tailwind-style breakpoints */
/* sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px */
/* Bootstrap-style breakpoints */
/* xs: <576px, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px */
/* Material Design breakpoints */
/* xs: 0-599px, sm: 600-1023px, md: 1024-1439px, lg: 1440-1919px, xl: 1920px+ */
/* Between breakpoints (range queries) */
@media (min-width: 768px) and (max-width: 1023px) {
/* Tablet only */
}
/* Level 4 syntax (cleaner) */
@media (768px <= width < 1024px) {
/* Tablet only */
}
/* Orientation-specific */
@media (min-width: 768px) and (orientation: portrait) {
/* Tablet portrait */
}
@media (min-width: 768px) and (orientation: landscape) {
/* Tablet landscape */
}
Responsive Design Best Practices
- Mobile-first is recommended: progressive enhancement, better performance
- Use
min-widthfor mobile-first,max-widthfor desktop-first - Combine viewport queries (layout) + container queries (components)
- Use
clamp()for fluid typography and spacing (reduces breakpoints) - Standard breakpoints: 640px, 768px, 1024px, 1280px, 1536px
- Test on real devices, not just browser DevTools
- Use
srcsetand<picture>for responsive images - Respect
prefers-reduced-motionand accessibility preferences - Touch devices:
(hover: none)and(pointer: coarse) - Use
100dvhinstead of100vhfor mobile full-height