Introduction to HTML & CSS · Lesson 4 of 5
Responsive Design & Media Queries
Responsive Web Design
A responsive website adapts its layout to work well on any screen — from a 320px phone to a 4K monitor. This is not optional. Over 60% of web traffic is mobile.
The Viewport Meta Tag
Without this, mobile browsers render pages at desktop width (980px) and scale them down. Always include it:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />Media Queries
Media queries apply CSS only when certain conditions are true.
/* Basic syntax */
@media (max-width: 768px) {
/* styles for screens 768px wide or smaller */
}
@media (min-width: 768px) {
/* styles for screens 768px wide or larger */
}
/* Range (modern syntax) */
@media (width >= 768px) and (width < 1024px) { }
/* Multiple conditions */
@media (min-width: 768px) and (orientation: landscape) { }
/* Dark mode preference */
@media (prefers-color-scheme: dark) { }
/* Reduced motion preference */
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.01ms !important; }
}
/* Print */
@media print {
.nav, .sidebar, .ads { display: none; }
}Mobile-First Design
Write CSS for mobile first, then add media queries for larger screens.
This is the recommended approach because:
- Mobile styles are simpler (single column, no complex layout)
- Adding features is easier than removing them
- Smaller base CSS, progressively enhanced
/* Mobile-first approach */
/* Base styles — mobile */
.card-grid {
display: grid;
grid-template-columns: 1fr; /* single column on mobile */
gap: 16px;
}
/* Tablet and up */
@media (min-width: 640px) {
.card-grid {
grid-template-columns: repeat(2, 1fr); /* 2 columns */
}
}
/* Desktop */
@media (min-width: 1024px) {
.card-grid {
grid-template-columns: repeat(3, 1fr); /* 3 columns */
}
}Standard Breakpoints
These match Tailwind CSS breakpoints (widely adopted):
/* sm */ @media (min-width: 640px) { }
/* md */ @media (min-width: 768px) { }
/* lg */ @media (min-width: 1024px) { }
/* xl */ @media (min-width: 1280px) { }
/* 2xl*/ @media (min-width: 1536px) { }Avoid too many breakpoints. Most designs need 2–3.
Fluid Typography with clamp()
clamp(min, preferred, max) scales a value between a minimum and maximum.
/* Font size that scales from 16px (mobile) to 24px (desktop) */
h1 {
font-size: clamp(1.5rem, 4vw, 2.5rem);
/* min preferred max */
}
p {
font-size: clamp(1rem, 1.5vw, 1.125rem);
}
/* Fluid spacing */
.section {
padding: clamp(40px, 8vw, 100px);
}This eliminates the need for font-size media queries in many cases.
Flexible Layouts
Fluid Grid (auto-fill)
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
gap: 20px;
}
/* Cards are min 280px wide but fill the row. No media queries needed. */Responsive Navigation
/* Mobile: hamburger */
.nav-links { display: none; }
.hamburger { display: block; }
/* Desktop: show links, hide hamburger */
@media (min-width: 768px) {
.nav-links { display: flex; }
.hamburger { display: none; }
}Stack to Row Pattern
.hero {
display: flex;
flex-direction: column; /* stack on mobile */
gap: 24px;
}
@media (min-width: 768px) {
.hero {
flex-direction: row; /* side by side on desktop */
align-items: center;
}
}Responsive Images
<!-- Basic: let image scale with container -->
<img src="photo.jpg" alt="Description" />
<style>
img {
max-width: 100%; /* never wider than container */
height: auto; /* maintain aspect ratio */
display: block;
}
</style>srcset — Different Sizes for Different Screens
<!-- Browser picks the right size based on screen -->
<img
src="photo-800.jpg"
srcset="
photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w
"
sizes="
(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw
"
alt="Photo description"
/>Picture — Art Direction (Different Crops)
<picture>
<!-- Portrait crop for mobile -->
<source
media="(max-width: 640px)"
srcset="photo-portrait.jpg"
/>
<!-- Landscape for desktop -->
<source
media="(min-width: 641px)"
srcset="photo-landscape.jpg"
/>
<!-- Fallback -->
<img src="photo-landscape.jpg" alt="Photo" />
</picture>CSS Container Queries
Newer than media queries — respond to the container's size, not the viewport's.
/* Define a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Style the card based on its container's width */
@container card (min-width: 400px) {
.card {
display: flex;
flex-direction: row;
}
.card img {
width: 160px;
flex-shrink: 0;
}
}Container queries are perfect for reusable components that need to adapt to wherever they're placed, regardless of viewport size.
Complete Responsive Layout Example
:root {
--max-width: 1200px;
--spacing-sm: 16px;
--spacing-md: 24px;
--spacing-lg: 48px;
--spacing-xl: 80px;
}
/* Page wrapper */
.page {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
/* Constrained width + centered */
.container {
width: 100%;
max-width: var(--max-width);
margin-inline: auto;
padding-inline: clamp(16px, 4vw, 48px);
}
/* Header */
.header {
padding-block: var(--spacing-sm);
}
/* Hero — stacks on mobile, side-by-side on desktop */
.hero {
padding-block: clamp(40px, 10vw, 120px);
display: grid;
gap: var(--spacing-lg);
align-items: center;
}
@media (min-width: 768px) {
.hero { grid-template-columns: 1fr 1fr; }
}
.hero h1 {
font-size: clamp(2rem, 5vw, 4rem);
line-height: 1.1;
}
/* Content sections */
.section {
padding-block: clamp(var(--spacing-lg), 8vw, var(--spacing-xl));
}
/* Card grid — fluid, no breakpoints needed */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
gap: var(--spacing-md);
}
/* Feature section — stack on mobile, split on desktop */
.feature {
display: grid;
gap: var(--spacing-md);
}
@media (min-width: 1024px) {
.feature { grid-template-columns: 1fr 1fr; }
.feature.reverse .feature-image { order: -1; }
}
/* Sidebar layout */
.with-sidebar {
display: grid;
gap: var(--spacing-md);
}
@media (min-width: 900px) {
.with-sidebar {
grid-template-columns: 240px 1fr;
}
}Testing Responsive Design
- Chrome DevTools: F12 → Toggle device toolbar (Ctrl+Shift+M)
- Resize browser window manually across breakpoints
- Real device testing: BrowserStack or your own phone
- Accessibility: Test with keyboard navigation and screen reader
Key Takeaways
- Mobile-first: write base CSS for mobile, use
min-widthmedia queries to enhance clamp()for fluid typography and spacing without media queriesauto-fill+minmaxfor responsive grids without breakpointsmax-width: 100%; height: autoon all images- Container queries for component-level responsiveness
- Test on real devices — emulators miss touch and performance issues