Responsive web design is an approach to web design that makes web pages render well on a variety of devices and window or screen sizes. This guide covers core responsive design principles and techniques using CSS.
Always include the viewport meta tag in your HTML to ensure proper scaling on mobile devices:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
This tag tells the browser to set the width of the viewport to the device width and set the initial zoom level to 1.
/* Base styles for mobile */
.element {
width: 100%;
font-size: 16px;
}
/* Enhance for larger screens */
@media (min-width: 768px) {
.element {
width: 50%;
font-size: 18px;
}
}
Start with styles for mobile devices, then use min-width
media queries to enhance for larger screens.
/* Base styles for desktop */
.element {
width: 50%;
font-size: 18px;
}
/* Adapt for smaller screens */
@media (max-width: 768px) {
.element {
width: 100%;
font-size: 16px;
}
}
Start with styles for desktop, then use max-width
media queries to adapt for smaller screens.
Fluid layouts use relative units instead of fixed pixels to create designs that adapt to different screen sizes.
.container {
width: 80%; /* Relative to parent element */
margin: 0 auto;
}
.column {
width: 33.333%; /* One-third of parent */
float: left;
}
.hero {
width: 100vw; /* 100% viewport width */
height: 50vh; /* 50% viewport height */
}
.text {
font-size: 5vmin; /* Relative to smaller dimension */
}
html {
font-size: 16px; /* Base font size */
}
.container {
width: 50em; /* Relative to font size of container */
}
h1 {
font-size: 2rem; /* Relative to root font size */
margin-bottom: 1.5rem;
}
p {
font-size: 1rem;
line-height: 1.5;
}
.fluid-columns {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.fluid-column {
flex: 1; /* Grows to fill available space */
min-width: 200px; /* Ensures columns wrap on small screens */
}
/* Apply box-sizing to all elements */
*, *:before, *:after {
box-sizing: border-box;
}
The box-sizing: border-box;
property includes padding and border in an element's total width and height, making it easier to create consistent layouts.
.container {
width: 80%;
max-width: 1200px; /* Prevents getting too wide */
min-width: 320px; /* Prevents getting too narrow */
margin: 0 auto;
}
Using max-width
and min-width
helps control element sizing across different devices.
Responsive typography ensures text is readable across different screen sizes.
Paragraph text (1em) that scales with the base font size of the parent element.
html {
font-size: 16px; /* Base size */
}
.responsive-text h1 {
font-size: 2em; /* 32px */
}
.responsive-text p {
font-size: 1em; /* 16px */
}
This paragraph uses viewport units to scale based on screen width.
.clamp-heading {
font-size: clamp(1.5rem, 5vw, 3rem);
}
.clamp-paragraph {
font-size: clamp(1rem, 2vw, 1.25rem);
}
The clamp()
function creates fluid typography with minimum and maximum bounds:
h1 {
/* Minimum: 1.5rem, Preferred: 5vw, Maximum: 3rem */
font-size: clamp(1.5rem, 5vw, 3rem);
}
p {
font-size: clamp(1rem, calc(0.875rem + 0.5vw), 1.25rem);
line-height: 1.5;
}
/* Base typography */
body {
font-size: 16px;
}
h1 {
font-size: 2rem;
}
/* Adjustments for larger screens */
@media (min-width: 768px) {
body {
font-size: 18px;
}
h1 {
font-size: 2.5rem;
}
}
p {
font-size: 1rem;
line-height: 1.5; /* Unitless value is best practice */
}
h1 {
font-size: 2.5rem;
line-height: 1.2;
}
Using unitless line-height values allows for proper scaling with font size changes.
Media queries allow you to apply different styles based on device characteristics like screen width, height, or orientation.
@media media-type and (media-feature) {
/* CSS rules */
}
width
, min-width
, max-width
height
, min-height
, max-height
orientation
(portrait or landscape)aspect-ratio
resolution
hover
(ability to hover)prefers-color-scheme
(light or dark mode)prefers-reduced-motion
.media-queries-demo {
background-color: #3498db; /* Default (large screens) */
}
@media (max-width: 768px) {
.media-queries-demo {
background-color: #2ecc71; /* Medium screens */
}
}
@media (max-width: 480px) {
.media-queries-demo {
background-color: #e74c3c; /* Small screens */
}
}
While breakpoints should be based on your design needs, here are some common ones:
/* Mobile first approach */
/* Base styles for mobile */
/* Small tablets and large phones */
@media (min-width: 576px) { ... }
/* Tablets and small laptops */
@media (min-width: 768px) { ... }
/* Desktops and laptops */
@media (min-width: 992px) { ... }
/* Large desktops */
@media (min-width: 1200px) { ... }
/* Targets screens between 768px and 1024px */
@media (min-width: 768px) and (max-width: 1024px) { ... }
/* Targets screens in landscape mode */
@media (orientation: landscape) { ... }
/* Logical operators */
@media (min-width: 768px) and (orientation: landscape) { ... }
@media (min-width: 768px), (orientation: landscape) { ... }
/* Check if a CSS property is supported */
@supports (display: grid) {
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
}
/* Fallback for browsers that don't support grid */
@supports not (display: grid) {
.container {
display: flex;
flex-wrap: wrap;
}
.item {
width: calc(33.333% - 20px);
margin: 10px;
}
}
Responsive images scale appropriately for different screen sizes and load optimized versions based on device capabilities.
.responsive-image {
max-width: 100%; /* Never exceed container width */
height: auto; /* Maintain aspect ratio */
display: block; /* Remove extra space below image */
}
The picture
element provides more control over image loading based on media conditions:
<picture>
<source media="(min-width: 1024px)" srcset="large.jpg">
<source media="(min-width: 768px)" srcset="medium.jpg">
<img src="small.jpg" alt="Description" class="responsive-image">
</picture>
.hero {
width: 100%;
height: 50vh;
background-image: url('small.jpg');
background-size: cover;
background-position: center;
}
@media (min-width: 768px) {
.hero {
background-image: url('medium.jpg');
}
}
@media (min-width: 1200px) {
.hero {
background-image: url('large.jpg');
}
}
<img
src="small.jpg"
srcset="small.jpg 320w, medium.jpg 768w, large.jpg 1200w"
sizes="(max-width: 320px) 280px, (max-width: 768px) 720px, 1140px"
alt="Description"
>
This tells the browser which image to load based on the viewport size and device resolution.
Modern CSS provides powerful tools for creating responsive layouts.
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
}
Grid creates two-dimensional layouts that can automatically adjust based on available space. The minmax()
and auto-fill
/auto-fit
functions are particularly useful for responsive designs.
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.flex-item {
flex: 1 1 200px; /* grow shrink basis */
}
Flexbox excels at one-dimensional layouts and is ideal for navigation bars, card layouts, and vertically centered content.
.text-columns {
column-count: 3;
column-gap: 2em;
}
@media (max-width: 768px) {
.text-columns {
column-count: 2;
}
}
@media (max-width: 480px) {
.text-columns {
column-count: 1;
}
}
Multi-column layout is useful for flowing text in newspaper-like columns that adjust based on screen size.
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: 1fr 3fr;
gap: 20px;
}
@media (max-width: 768px) {
.page {
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
grid-template-columns: 1fr;
}
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
/* Using flexbox within grid areas */
.content {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
Container queries allow styles to be applied based on the size of a parent container rather than the viewport, enabling truly modular responsive components.
Resize this container horizontally to see the layout change (requires browser support).
/* Example Container Query Syntax (modern browsers) */
.container {
container-type: inline-size;
container-name: sidebar-layout;
}
@container sidebar-layout (min-width: 700px) {
.layout {
display: flex;
}
.sidebar {
width: 200px;
}
}
@container sidebar-layout (max-width: 699px) {
.layout {
display: block;
}
.sidebar {
width: 100%;
}
}
.viewport-units-demo {
width: 80vw; /* 80% of viewport width */
height: 40vh; /* 40% of viewport height */
font-size: 3vmin; /* 3% of viewport's smaller dimension */
}
Viewport units (vw
, vh
, vmin
, vmax
) size elements relative to the viewport dimensions.
/* Modern approach with aspect-ratio property */
.video-container {
width: 100%;
aspect-ratio: 16 / 9;
background: #000;
}
/* Older approach with padding hack */
.video-container-legacy {
width: 100%;
position: relative;
padding-bottom: 56.25%; /* 16:9 aspect ratio (9/16 = 0.5625) */
}
.video-container-legacy iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* Media query for touch devices */
@media (hover: none) and (pointer: coarse) {
/* Styles for touch devices */
.button {
padding: 12px 24px; /* Larger touch target */
}
}
@media (hover: hover) {
/* Styles for devices with hover capability */
.card:hover {
transform: translateY(-5px);
}
}
.navbar {
background-color: #2c3e50;
color: white;
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-menu {
display: flex;
gap: 20px;
}
.nav-toggle {
display: none; /* Hidden on desktop */
}
@media (max-width: 768px) {
.nav-menu {
position: fixed;
left: -100%;
top: 70px;
flex-direction: column;
width: 100%;
text-align: center;
transition: 0.3s;
padding: 20px 0;
}
.nav-menu.active {
left: 0;
}
.nav-toggle {
display: block; /* Visible on mobile */
}
}
This is a responsive card layout that adjusts based on screen size.
Cards will wrap to new rows when there's not enough space.
Each card has a minimum width but will grow to fill available space.
.card-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 300px; /* grow shrink basis */
}
Name | Age | Location | Occupation |
---|---|---|---|
John Doe | 32 | New York | Developer |
Jane Smith | 28 | London | Designer |
Bob Johnson | 45 | Paris | Manager |
/* Basic responsive table with horizontal scrolling */
.responsive-table {
width: 100%;
border-collapse: collapse;
}
@media (max-width: 768px) {
.responsive-table {
display: block;
overflow-x: auto;
}
}
/* Card-based approach for very small screens */
@media (max-width: 480px) {
.responsive-table, .responsive-table tbody, .responsive-table tr,
.responsive-table th, .responsive-table td {
display: block;
width: 100%;
}
.responsive-table td {
position: relative;
padding-left: 50%;
}
.responsive-table td:before {
position: absolute;
left: 12px;
width: 45%;
font-weight: bold;
content: attr(data-label);
}
}
@supports
for newer CSS featuresTwo-dimensional layout system
One-dimensional layout
Component-level responsive design
/* Base styles everyone gets */
.layout {
display: block;
}
.column {
width: 100%;
margin-bottom: 20px;
}
/* Flexbox enhancement */
@supports (display: flex) {
.layout {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.column {
flex: 1 1 300px;
margin-bottom: 0;
}
}
/* Grid enhancement */
@supports (display: grid) {
.layout {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.column {
/* No need for flex properties */
}
}