What is Responsive Design?
Responsive design makes websites work well on all device sizes - from phones to tablets to desktops.
Key techniques:
Media Queries - Apply styles based on screen size
Flexible Layouts - Flexbox & Grid that adapt
Responsive Units - rem, em, %, vw, vh
Mobile-First - Design for small screens first
Apply styles based on device characteristics.
Basic Syntax
@media type and (condition) {
/* Styles */
}
Screen Size - min-width
Screen Size - max-width
Range
/* Styles for screens 768px and wider */
@media screen and ( min-width : 768 px ) {
.container {
max-width : 720 px ;
}
}
Standard Breakpoints
Common device breakpoints:
/* Mobile phones */
@media ( max-width : 480 px ) { }
/* Tablets portrait */
@media ( min-width : 481 px ) and ( max-width : 768 px ) { }
/* Tablets landscape / Small laptops */
@media ( min-width : 769 px ) and ( max-width : 1024 px ) { }
/* Laptops / Desktops */
@media ( min-width : 1025 px ) and ( max-width : 1200 px ) { }
/* Large desktops */
@media ( min-width : 1201 px ) { }
Project Breakpoints
/* From the tutorial project */
/* Tablet and smaller */
@media screen and ( max-width : 768 px ) {
/* Tablet optimizations */
}
/* Small mobile */
@media screen and ( max-width : 480 px ) {
/* Phone optimizations */
}
Mobile-First vs Desktop-First
Desktop-First (max-width)
/* Base: Desktop styles */
.container {
width : 1200 px ;
}
/* Then override for smaller screens */
@media ( max-width : 768 px ) {
.container {
width : 100 % ;
}
}
Mobile-First (min-width) - Recommended! ⭐
/* Base: Mobile styles */
.container {
width : 100 % ;
}
/* Then enhance for larger screens */
@media ( min-width : 768 px ) {
.container {
width : 720 px ;
}
}
@media ( min-width : 1200 px ) {
.container {
width : 1200 px ;
}
}
Mobile-first is recommended because:
Forces you to prioritize content
Better performance on mobile (loads less CSS)
Progressive enhancement approach
Most traffic is mobile
Real Examples from the Project
/* Base (mobile) styles */
.header__container {
display : flex ;
align-items : center ;
justify-content : space-between ;
gap : var ( --spacing-md );
}
/* Tablet and below */
@media screen and ( max-width : 768 px ) {
.header__container {
flex-wrap : wrap ; /* Allow wrapping */
padding : var ( --spacing-sm ) var ( --spacing-md );
}
/* Logo smaller */
.header__logo-text {
font-size : var ( --font-size-xl );
}
/* Search takes full width */
.header__search {
order : 3 ; /* Move to end */
flex-basis : 100 % ; /* Full width */
max-width : none ;
margin-top : var ( --spacing-sm );
}
/* Nav spacing tighter */
.header__nav-list {
gap : var ( --spacing-sm );
}
}
Visually Hidden Text (Accessible)
@media screen and ( max-width : 768 px ) {
/* Hide cart label text but keep for screen readers */
.header__cart-label {
position : absolute ;
width : 1 px ;
height : 1 px ;
padding : 0 ;
margin : -1 px ;
overflow : hidden ;
clip : rect ( 0 , 0 , 0 , 0 );
white-space : nowrap ;
border : 0 ;
}
}
This technique hides content visually but keeps it accessible to screen readers - better than display: none.
Hero Section
/* Base */
.hero {
padding : var ( --spacing-2xl ) var ( --spacing-lg );
}
.hero__title {
font-size : var ( --font-size-3xl );
}
/* Tablet */
@media screen and ( max-width : 768 px ) {
.hero {
padding : var ( --spacing-xl ) var ( --spacing-md );
}
.hero__title {
font-size : var ( --font-size-2xl ); /* Smaller title */
}
}
Navigation - Mobile Vertical
/* Base */
.header__nav-list {
display : flex ;
align-items : center ;
gap : var ( --spacing-md );
}
/* Small mobile */
@media screen and ( max-width : 480 px ) {
.header__nav-list {
flex-direction : column ; /* Stack vertically */
align-items : flex-end ;
gap : var ( --spacing-xs );
}
}
Grid - Single Column Mobile
/* Base - responsive grid */
.products__grid {
display : grid ;
grid-template-columns : repeat ( auto-fill , minmax ( 280 px , 1 fr ));
gap : var ( --spacing-lg );
}
/* Force single column on small mobile */
@media screen and ( max-width : 480 px ) {
.products__grid {
grid-template-columns : 1 fr ;
}
.benefits__grid {
grid-template-columns : 1 fr ;
}
}
/* Base */
.footer__bottom {
display : flex ;
justify-content : space-between ;
gap : var ( --spacing-md );
}
/* Tablet */
@media screen and ( max-width : 768 px ) {
.footer__bottom {
flex-direction : column ; /* Stack */
text-align : center ;
}
}
Screen (Most Common)
@media screen and ( max-width : 768 px ) {
/* Styles for screens */
}
Print
@media print {
.no-print {
display : none ; /* Hide on print */
}
body {
color : black ;
background : white ;
}
}
All (Default)
@media ( max-width : 768 px ) {
/* Applies to all media types */
}
prefers-color-scheme (Dark Mode)
/* Light mode (default) */
:root {
--color-bg : #FFFFFF ;
--color-text : #333333 ;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--color-bg : #1a1a1a ;
--color-text : #f0f0f0 ;
}
}
/* Usage - automatically adapts! */
body {
background-color : var ( --color-bg );
color : var ( --color-text );
}
prefers-reduced-motion (Accessibility)
/* Normal animations */
.element {
transition : transform 300 ms ease ;
}
/* Respect user preference for reduced motion */
@media (prefers-reduced-motion: reduce) {
* ,
* ::before ,
* ::after {
animation-duration : 0.01 ms !important ;
animation-iteration-count : 1 !important ;
transition-duration : 0.01 ms !important ;
scroll-behavior : auto !important ;
}
}
Always include prefers-reduced-motion - some users get motion sickness from animations.
Other Preference Queries
/* High contrast mode */
@media (prefers-contrast: high) {
.button {
border : 3 px solid currentColor ;
}
}
/* Reduced transparency */
@media (prefers-reduced-transparency) {
.element {
opacity : 1 !important ;
}
}
Orientation
/* Portrait (taller than wide) */
@media ( orientation : portrait ) {
.gallery {
grid-template-columns : repeat ( 2 , 1 fr );
}
}
/* Landscape (wider than tall) */
@media ( orientation : landscape ) {
.gallery {
grid-template-columns : repeat ( 4 , 1 fr );
}
}
Responsive Units
Relative Units
rem (Root EM)
em
% (Percentage)
vw / vh (Viewport)
/* Relative to root font-size (usually 16px) */
html {
font-size : 16 px ; /* 1rem = 16px */
}
.element {
font-size : 1.5 rem ; /* 24px */
padding : 2 rem ; /* 32px */
margin : 0.5 rem ; /* 8px */
}
Use rem for most sizing - it respects user’s browser font size settings (accessibility!).
Responsive Typography
h1 {
font-size : 1.5 rem ; /* Mobile */
}
@media ( min-width : 768 px ) {
h1 {
font-size : 2 rem ; /* Tablet */
}
}
@media ( min-width : 1200 px ) {
h1 {
font-size : 2.5 rem ; /* Desktop */
}
}
Fluid Typography with clamp()
h1 {
/* min, preferred, max */
font-size : clamp ( 1.5 rem , 4 vw , 3 rem );
/* Never smaller than 1.5rem, never larger than 3rem */
/* Scales smoothly in between based on viewport */
}
Responsive Images
CSS Approach
img {
max-width : 100 % ; /* Never overflow container */
height : auto ; /* Maintain aspect ratio */
}
HTML Approach (Better!)
<!-- Different images for different sizes -->
< picture >
< source media = "(min-width: 1200px)" srcset = "large.jpg" >
< source media = "(min-width: 768px)" srcset = "medium.jpg" >
< img src = "small.jpg" alt = "Description" >
</ picture >
<!-- Different resolutions -->
< img
srcset = "image-1x.jpg 1x, image-2x.jpg 2x"
src = "image-1x.jpg"
alt = "Description"
>
Container Queries (Modern!)
Style based on container size, not viewport.
/* Define container */
.card-container {
container-type : inline-size;
}
/* Query the container */
@container (min-width: 400px) {
.card {
display : flex ; /* Side-by-side when container is wide */
}
}
Container queries are new but very powerful - they let components be truly modular and reusable.
Responsive Grid Patterns
.grid {
display : grid ;
grid-template-columns : repeat ( auto-fit , minmax ( 250 px , 1 fr ));
gap : 20 px ;
}
/* Automatically adjusts columns based on available space:
* 1200px screen: 4 columns
* 800px screen: 3 columns
* 500px screen: 2 columns
* 300px screen: 1 column
*/
.grid {
display : grid ;
grid-template-columns : repeat ( auto-fit , minmax ( 250 px , 1 fr ));
gap : 20 px ;
}
/* Force single column on very small screens */
@media ( max-width : 480 px ) {
.grid {
grid-template-columns : 1 fr ;
}
}
Responsive Flexbox
Wrapping Layout
.row {
display : flex ;
flex-wrap : wrap ; /* Items wrap to next line */
gap : 20 px ;
}
.column {
flex : 1 1 300 px ; /* Grow, shrink, min 300px */
}
Changing Direction
.container {
display : flex ;
flex-direction : row ;
}
@media ( max-width : 768 px ) {
.container {
flex-direction : column ; /* Stack on mobile */
}
}
Reordering with order
.header {
display : flex ;
}
.logo { order : 1 ; }
.nav { order : 2 ; }
.search { order : 3 ; }
@media ( max-width : 768 px ) {
.search {
order : 1 ; /* Move search first on mobile */
flex-basis : 100 % ; /* Full width */
}
}
Responsive Spacing
Variable Spacing
:root {
--section-padding : var ( --spacing-xl ); /* 32px */
}
@media ( max-width : 768 px ) {
:root {
--section-padding : var ( --spacing-md ); /* 16px */
}
}
.section {
padding : var ( --section-padding ); /* Automatically responsive! */
}
Viewport-Based Spacing
.section {
padding : clamp ( 1 rem , 5 vw , 3 rem );
/* Min 1rem, max 3rem, scales with viewport */
}
Testing Responsive Design
Open DevTools (F12)
Click device toolbar icon (Ctrl+Shift+M)
Select device or enter custom dimensions
Test at different breakpoints
Common Test Sizes
320px - iPhone SE (small phone)
375px - iPhone X/11/12/13 (standard phone)
768px - iPad (tablet portrait)
1024px - iPad Pro (tablet landscape)
1366px - Laptop
1920px - Desktop
Best Practices
Use mobile-first approach
Test on real devices when possible
Use relative units (rem, %, vw) over px
Keep breakpoints simple (2-3 main breakpoints)
Make touch targets at least 44x44px on mobile
Test with real content (not Lorem ipsum)
Don’t hide important content on mobile
Don’t target specific devices (they change constantly)
Avoid horizontal scrolling
Common Responsive Patterns
/* Mobile: hamburger icon */
.nav-toggle {
display : block ;
}
.nav-menu {
display : none ; /* Hidden by default */
}
.nav-menu.active {
display : flex ;
flex-direction : column ;
}
/* Desktop: full navigation */
@media ( min-width : 768 px ) {
.nav-toggle {
display : none ;
}
.nav-menu {
display : flex ;
flex-direction : row ;
}
}
Responsive Table
/* Mobile: Cards */
@media ( max-width : 768 px ) {
table , thead , tbody , tr , th , td {
display : block ;
}
tr {
margin-bottom : 1 rem ;
border : 1 px solid #ddd ;
}
}
.sidebar {
position : fixed ;
left : -250 px ; /* Hidden off-screen */
width : 250 px ;
transition : left 300 ms ;
}
.sidebar.active {
left : 0 ; /* Slide in */
}
/* Desktop: always visible */
@media ( min-width : 1024 px ) {
.sidebar {
position : static ;
left : 0 ;
}
}
Complete Responsive Component
/* Product Card - Fully Responsive */
/* Base (Mobile) */
.product-card {
background-color : var ( --color-white );
border-radius : var ( --border-radius-md );
padding : var ( --spacing-md );
}
.product-card__image {
width : 100 % ;
aspect-ratio : 4 / 3 ;
object-fit : cover ;
}
.product-card__title {
font-size : var ( --font-size-base );
margin : var ( --spacing-sm ) 0 ;
}
/* Tablet */
@media ( min-width : 768 px ) {
.product-card {
padding : var ( --spacing-lg );
}
.product-card__title {
font-size : var ( --font-size-lg );
}
}
/* Desktop */
@media ( min-width : 1200 px ) {
.product-card:hover {
transform : translateY ( -8 px );
box-shadow : var ( --shadow-lg );
}
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.product-card {
transition : none ;
}
.product-card:hover {
transform : none ;
}
}
Always include in your HTML <head>:
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
Without this meta tag, mobile browsers will render at desktop width and zoom out - your media queries won’t work!
Quick Reference
min-width - At least this wide
max-width - At most this wide
orientation - portrait | landscape
prefers-color-scheme - light | dark
prefers-reduced-motion - reduce | no-preference
Responsive Units
rem - Relative to root font-size
em - Relative to parent font-size
% - Relative to parent
vw/vh - Viewport width/height
vmin/vmax - Smaller/larger of vw or vh
Functions
clamp(min, preferred, max) - Responsive sizing
min(value1, value2) - Use smaller value
max(value1, value2) - Use larger value
calc(expression) - Calculate values
Next Steps
Flexbox Build responsive layouts with Flexbox
Grid Create responsive grids