Cheat SheetsHTML, CSS & ResponsiveResponsive

Responsive — Cheat Sheet

HTML, CSS & Responsive · 4 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Responsive
HTML, CSS & Responsive4 topicsQuick revision reference
1

Media Queries, Breakpoints and Container Queries

Write mobile-first, choose breakpoints from where your content breaks rather than from device names, and use container queries when a component should respond to its own space.

  • Mobile-first with min-width means the smallest device parses the least CSS and overrides nothing
  • Breakpoints in rem respect the user's font size; breakpoints chosen from content beat device-named ones
  • Container queries let a component respond to its own width, which a media query cannot express
  • container-type creates a containment context, so apply it to a wrapper rather than the styled component
  • prefers-reduced-motion, hover and pointer queries matter as much as width — a phone has no hover and needs 44px targets
min-width, in rem, from content
/* Base: the smallest screen, no query needed */
.grid { display: grid; gap: 1rem; grid-template-columns: 1fr }

/* Then add complexity upwards */
@media (min-width: 48rem) {   /* 768px */
  .grid { grid-template-columns: repeat(2, 1fr) }
}
@media (min-width: 64rem) {   /* 1024px */
  .grid { grid-template-columns: repeat(3, 1fr) }
}

/* Desktop-first (max-width) means a phone parses every desktop rule
   and then overrides it — more CSS to override, and the smallest
   device does the most work. */

/* Use rem in the query, not px: the query then respects the user's
   font size, so a zoomed-in user gets the simpler layout that fits.

/* Modern range syntax, where supported */
@media (width >= 48rem) { }
@media (48rem <= width <= 64rem) { }

/* Breakpoints from content, not from device names. There is no
   "iPhone width" worth targeting — there are dozens. Common
   starting values, to be adjusted once you see your content:
     40rem (640)  48rem (768)  64rem (1024)  80rem (1280)         */
2

Fluid Type and Spacing

Scaling type and space continuously with clamp() replaces most sizing breakpoints and removes the jumps where a heading changes size mid-drag.

  • clamp() interpolates a value continuously, removing the jumps that breakpoint-based sizing produces
  • A preferred value in vw alone ignores the user's font-size setting — always include a rem term
  • Fluid spacing tokens fix both cramped phone padding and absurd desktop padding without media queries
  • width: min(100% - 2rem, 72rem) with margin-inline: auto is the complete content wrapper in two lines
  • Intrinsic patterns like auto-fit grids and flex-basis wrapping respond to the container, leaving media queries for real structural changes
Always mix rem into the preferred value
/* clamp(minimum, preferred, maximum) */
h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem) }
p  { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem) }

/* Why the preferred value is a SUM:
     clamp(2rem, 5vw, 3.5rem)          — pure vw: a user who doubles
                                          their browser font size sees
                                          no change at all
     clamp(2rem, 1.5rem + 2.5vw, 3.5rem) — the rem term keeps it
                                          responsive to that setting  */

/* Deriving the numbers: to go from 2rem at 320px to 3.5rem at 1280px
     slope = (3.5 - 2) / (1280 - 320) * 100vw  = 0.156vw per px = 15.6vw... */
/* In practice use a generator (utopia.fyi) rather than the algebra,
   and check both ends in the browser. */

/* A fluid scale, defined once as tokens */
:root {
  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.94rem);
  --step-0:  clamp(1rem,    0.96rem + 0.2vw, 1.13rem);
  --step-1:  clamp(1.2rem,  1.14rem + 0.3vw, 1.41rem);
  --step-2:  clamp(1.44rem, 1.35rem + 0.45vw, 1.76rem);
}
h2 { font-size: var(--step-2) }
3

Responsive Images and Media

Images are usually the largest thing on a page. srcset, modern formats and a reserved aspect ratio decide both how fast the page loads and whether it jumps while loading.

  • srcset lists the available files and sizes describes the rendered width — omitting sizes makes the browser assume 100vw
  • picture with AVIF and WebP sources roughly halves image bytes with a JPEG fallback
  • width and height attributes let the browser reserve space and are the main defence against layout shift
  • aspect-ratio with object-fit: cover handles images whose dimensions are not known in advance
  • Never lazy-load the hero image — it is the LCP element and should be preloaded with high fetch priority
srcset for files, sizes for layout
<!-- Density switching: same size, different resolutions -->
<img src="logo.png" srcset="logo.png 1x, logo@2x.png 2x" alt="AiCanCode">

<!-- Width switching: different sizes for different layouts -->
<img
  src="hero-800.jpg"
  srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
  sizes="(min-width: 64rem) 50vw, 100vw"
  width="1600" height="900"
  alt="…">

<!-- srcset says how WIDE each file is.
     sizes says how wide the IMAGE will be at each breakpoint.
     The browser combines them with the device pixel ratio and picks.

     Omitting sizes makes the browser assume 100vw and download a
     file that is often twice as large as needed. -->

<!-- Format negotiation: AVIF, then WebP, then a fallback -->
<picture>
  <source type="image/avif" srcset="hero.avif">
  <source type="image/webp" srcset="hero.webp">
  <img src="hero.jpg" alt="…" width="1600" height="900">
</picture>

<!-- Art direction: a genuinely different crop on a phone -->
<picture>
  <source media="(max-width: 40rem)" srcset="hero-square.jpg">
  <img src="hero-wide.jpg" alt="…">
</picture>
4

Responsive Patterns and Testing

Navigation, tables and forms are where responsive designs actually break. Each has a known set of solutions, and each needs testing on a real device rather than a resized window.

  • A navigation toggle needs aria-expanded, aria-controls, focus management and Escape — the CSS is the easy half
  • Inputs below 16px make iOS zoom the page; fix the font size rather than blocking zoom
  • user-scalable=no is a WCAG violation — never disable pinch zoom
  • Touch targets need roughly 44px and spacing between them, and primary actions belong within thumb reach
  • Throttle CPU and network, test at 200% zoom, and verify on a real mid-range Android — DevTools cannot show the on-screen keyboard or true scroll performance
aria-expanded, focus, and alternatives to the hamburger
/* Base: the phone. A toggle and a hidden panel. */
.nav-toggle { display: block }
.nav-list { display: none }
.nav-list[data-open] { display: flex; flex-direction: column }

@media (min-width: 48rem) {
  .nav-toggle { display: none }
  .nav-list { display: flex; flex-direction: row; gap: 1.5rem }
}

<!-- The toggle must announce its state, and control the panel -->
<button class="nav-toggle" aria-expanded="false" aria-controls="nav-list">
  <span class="sr-only">Menu</span>
  <svg aria-hidden="true">…</svg>
</button>
<ul id="nav-list">…</ul>

/* When the drawer is open: trap focus inside it, close on Escape,
   return focus to the toggle, and lock body scroll. A drawer that
   leaves focus behind it is a keyboard trap in reverse — the user
   tabs into a menu they cannot see. */

/* Alternatives to a hamburger, both often better:
     - a visible row that scrolls horizontally
     - the priority+ pattern: show what fits, "More" for the rest
   A hamburger hides navigation, which measurably reduces its use. */
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/html-css