Episode 1 — Fundamentals / 1.9 — CSS Responsive Design

1.9.c — Breakpoint Planning

In one sentence: Good breakpoints are driven by where your content breaks, not by the latest iPhone width — plan them early, keep them few, and encode them as reusable tokens.

Navigation: ← 1.9.b — Media Queries · 1.9.d — Responsive Images →


1. Device-driven vs content-driven breakpoints

Device-driven (fragile)

Pick breakpoints based on popular devices: 375px (iPhone), 768px (iPad), 1440px (MacBook). Looks fine today, breaks tomorrow when new devices ship.

Content-driven (resilient)

Resize your browser slowly. Where does the content look bad? That's your breakpoint. This approach survives device turnover because it follows the content, not the hardware.

Slowly drag the viewport edge →
──────────────────────────────────────────────────────
 ▏320      480      640      768      1024     1280  ▕
 ▏                                                    ▕
 ▏  "Text line gets                                   ▕
 ▏   too long here"  ← breakpoint!                    ▕
 ▏                        "Cards squish"  ← breakpoint!

Interview tip: Say "I set breakpoints where the design breaks, not at device widths" — interviewers love hearing you think about content first.


2. Common breakpoint ranges

Even with content-driven breakpoints, projects need a shared vocabulary. These ranges cover the vast majority of viewports:

NameRangeTypical devices
xs (mobile)0 – 479pxSmall phones
sm (large mobile)480 – 639pxLarge phones, small tablets
md (tablet)640 – 1023pxTablets, small laptops
lg (desktop)1024 – 1279pxLaptops, standard monitors
xl (wide)1280 – 1535pxLarge monitors
2xl (ultra-wide)1536px+Ultra-wide, 4K monitors
/* Using min-width (mobile-first) */
/* xs: base styles — no query needed */

/* sm */
@media (min-width: 480px) { … }

/* md */
@media (min-width: 640px) { … }

/* lg */
@media (min-width: 1024px) { … }

/* xl */
@media (min-width: 1280px) { … }

/* 2xl */
@media (min-width: 1536px) { … }

Note: These are guidelines, not rules. Adjust to your content. Many projects only need 2–3 breakpoints.


3. The "major" and "minor" breakpoint pattern

Not every breakpoint needs a full layout shift. Distinguish between:

TypePurposeExample
MajorLayout restructuring (columns, navigation pattern)Stack → 2-col → 3-col grid
MinorTweaks within a layout (spacing, font size, padding)Increase card padding from 1rem to 2rem
/* Minor: just spacing */
@media (min-width: 480px) {
  .card { padding: 1.5rem; }
}

/* Major: layout change */
@media (min-width: 768px) {
  .page {
    display: grid;
    grid-template-columns: 250px 1fr;
  }
}

/* Minor: wider spacing */
@media (min-width: 1024px) {
  .page { gap: 3rem; }
}

4. Breakpoint token system

Hard-coding pixel values throughout your CSS creates a maintenance nightmare. Use custom properties or preprocessor variables as breakpoint tokens.

CSS custom properties (limited)

CSS custom properties can't be used inside @media conditions directly. But you can use them for spacing/sizing that changes at breakpoints:

:root {
  --container-max: 100%;
  --gutter: 1rem;
}

@media (min-width: 768px) {
  :root {
    --container-max: 720px;
    --gutter: 1.5rem;
  }
}

@media (min-width: 1024px) {
  :root {
    --container-max: 960px;
    --gutter: 2rem;
  }
}

.container {
  max-width: var(--container-max);
  padding-inline: var(--gutter);
  margin-inline: auto;
}

Sass variables (can be used in queries)

$bp-sm:  480px;
$bp-md:  768px;
$bp-lg:  1024px;
$bp-xl:  1280px;

@mixin from($bp) {
  @media (min-width: $bp) { @content; }
}

.grid {
  display: grid;
  gap: 1rem;

  @include from($bp-md) {
    grid-template-columns: repeat(2, 1fr);
  }

  @include from($bp-lg) {
    grid-template-columns: repeat(3, 1fr);
  }
}

5. The container-width problem

Responsive design based on viewport width can fail when a component lives inside a narrow sidebar. The sidebar might be 300px wide on a 1440px screen — but your min-width: 1024px query already fired.

Solution (preview): CSS Container Queries (@container) let components respond to their container's size, not the viewport's. This is covered in advanced CSS, but knowing the limitation of viewport-based breakpoints matters now.

.card-wrapper {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card { display: flex; gap: 1rem; }
}

6. Testing breakpoints with DevTools

Chrome / Edge device toolbar

  1. Open DevTools → click the device toolbar icon (or Ctrl+Shift+M / Cmd+Shift+M).
  2. Select Responsive mode → drag the width handle.
  3. Click dimensions dropdown → add custom device sizes matching your breakpoints.

Firefox responsive mode

  1. Ctrl+Shift+M / Cmd+Shift+MResponsive Design Mode.
  2. Type exact pixel widths in the input fields.
  3. Toggle touch simulation for testing pointer: coarse.

What to test

CheckWhat to look for
Slow dragResize from 320px to 1920px — watch for content that overflows, collapses, or gaps
Breakpoint boundariesTest 1px below and above each breakpoint
OrientationRotate between portrait and landscape
Text zoomBrowser zoom to 200% — layout should not break
Real devicesEmulators miss scrollbar width, safe areas, notches

7. Avoiding breakpoint sprawl

GuidelineReasoning
Start with 0 breakpointsLet the content flow naturally first
Add breakpoints only when the layout breaksFewer queries = less complexity
Cap at 3–5 breakpoints for most projectsBeyond that, consider fluid sizing instead
Use fluid techniques firstclamp(), minmax(), auto-fit reduce the need for explicit breakpoints
/* This grid needs ZERO breakpoints */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

8. Key takeaways

  1. Content-driven breakpoints outlast device-driven ones.
  2. Use a small set of shared breakpoint tokens — don't scatter magic numbers.
  3. Distinguish major (layout change) from minor (spacing tweak) breakpoints.
  4. Test by slowly dragging the viewport, not just snapping to device sizes.
  5. Fluid techniques (auto-fit, clamp()) can eliminate breakpoints entirely.

Explain-It Challenge

Explain without notes:

  1. Why is "set a breakpoint at 768px because iPads are 768px" a fragile strategy?
  2. How would you determine where breakpoints belong for a brand-new design that has no mockups for tablet sizes?
  3. What problem do CSS Container Queries solve that viewport-based media queries cannot?

Navigation: ← 1.9.b — Media Queries · 1.9.d — Responsive Images →