CSS Responsive Design

Responsive design makes a website work well on any screen size, from a small phone to a large desktop monitor. The core tools are media queries, flexible layouts (Flexbox and Grid), and fluid units.

Viewport meta tag

Add this tag inside <head> on every page. Without it, mobile browsers render the page at desktop width and then scale it down, which breaks media queries.

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>

width=device-width sets the viewport to the device’s actual screen width. initial-scale=1.0 prevents the browser from zooming in or out on load.

Mobile-first approach

Write your base CSS for mobile screens first, then use min-width media queries to layer in styles for larger screens. Mobile CSS is usually simpler, so starting there keeps your default styles clean.

/* Base styles: mobile (no media query needed) */
.nav {
  flex-direction: column;
}

/* Tablet and up */
@media (min-width: 768px) {
  .nav {
    flex-direction: row;
  }
}

The alternative, desktop-first, uses max-width queries to narrow styles down to smaller screens. Either approach works, but mobile-first is the more common convention.

Media queries

A media query applies CSS only when a condition is true, usually a screen width.

/* Mobile: single column (default, no media query) */
.grid {
  display: grid;
  grid-template-columns: 1fr;
}

/* Tablet and up */
@media (min-width: 768px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Desktop and up */
@media (min-width: 1024px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

Common breakpoints used in practice (these are starting points, not rules):

  • 480px: small phones
  • 768px: tablets
  • 1024px: small desktops
  • 1280px: large desktops

You can also query for height, orientation, or resolution:

@media (orientation: landscape) {
  .hero {
    min-height: 50vh;
  }
}

@media (min-resolution: 2dppx) {
  /* Styles for high-density (retina) screens */
}

Responsive units

Fixed pixel values don’t scale with the user’s font size preferences. These units do.

UnitRelative to
emParent element’s font size
remRoot (html) font size
%Parent element’s dimension
vw1% of viewport width
vh1% of viewport height
html {
  font-size: 16px; /* 1rem = 16px */
}

h1 {
  font-size: 2rem;    /* 32px */
  margin-bottom: 1em; /* relative to h1's own font size */
}

.container {
  width: 90%;         /* 90% of the parent */
  max-width: 1200px;
}

.hero {
  height: 100vh;      /* full viewport height */
}

Prefer rem for font sizes. It respects the user’s browser font size setting and makes your whole site scale consistently.

clamp() for fluid typography

clamp() lets a value scale smoothly between a minimum and maximum based on the viewport width. No media queries needed.

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

The three arguments are: minimum, preferred (scales with viewport), maximum. Here the heading is never smaller than 1.5rem or larger than 3rem, and scales fluidly between those limits.

min() and max()

min() picks the smaller of two values. max() picks the larger.

.container {
  /* Full width on small screens, capped at 1200px on large screens */
  width: min(100%, 1200px);
}

.text {
  /* At least 1rem, or 2vw if that is larger */
  font-size: max(1rem, 2vw);
}

These are useful alternatives to media queries for simple responsive sizing.

Container queries

Media queries respond to the viewport size. Container queries respond to the size of a parent element. This is useful for reusable components that appear in different-sized contexts.

/* Mark the parent as a container */
.sidebar {
  container-type: inline-size;
}

/* Apply styles when the container is at least 400px wide */
@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

Container queries are supported in all modern browsers. They are especially useful in component-based projects where you don’t know ahead of time how wide a container will be.

Responsive images

img {
  max-width: 100%;
  height: auto;
}

max-width: 100% stops images from overflowing their container. height: auto maintains the original aspect ratio.

  • Flexbox : one-dimensional layouts with rows and columns
  • CSS Grid : two-dimensional layouts