Breakpoints
Define viewport breakpoint tokens and use responsive variants for page-level layout, typography, and density changes.
Overview
Breakpoints are viewport thresholds. They answer one question: when the available page width changes, which product-level decisions should change with it?
Use breakpoint variants for navigation modes, app shells, page grids, typography shifts, and density changes that should follow the viewport. Use containers when a reusable component should respond to the size of its parent instead.
Master CSS defines breakpoint tokens in the theme layer. The variant syntax is @<name>, so @md reads from breakpoint-md.
| Token | Value | PX | Description |
|---|---|---|---|
--breakpoint-4xs | 22.5rem | 360px | Small phone and compact embedded surfaces. |
--breakpoint-3xs | 30rem | 480px | Large phone or narrow split-pane entry point. |
--breakpoint-2xs | 37.5rem | 600px | Small tablet, large modal, and compact app shell width. |
--breakpoint-xs | 48rem | 768px | Tablet portrait or roomy mobile layout. |
--breakpoint-sm | 52.125rem | 834px | Tablet landscape and small desktop layout. |
--breakpoint-md | 64rem | 1024px | Default desktop shell threshold. |
--breakpoint-lg | 80rem | 1280px | Wide desktop layout with stronger horizontal composition. |
--breakpoint-xl | 90rem | 1440px | Large desktop or high-density canvas. |
--breakpoint-2xl | 100rem | 1600px | Expanded workstation viewport. |
--breakpoint-3xl | 120rem | 1920px | Very wide product or editorial canvas. |
--breakpoint-4xl | 160rem | 2560px | Maximum viewport-oriented layout threshold. |
Define breakpoint variables
Breakpoint variables belong in your project CSS entry. Keep them product-wide and stable; they are part of the layout language shared by docs, components, designers, and tests.
@theme { --breakpoint-sm: 48rem; --breakpoint-md: 64rem; --breakpoint-lg: 80rem;}Use CSS length values for breakpoint tokens; rem keeps thresholds aligned with the root font size. Unitless numbers are still accepted and interpreted on the 16px scale for existing projects. The scale tables show px/rem pairs for readability, while generated queries use the normalized rem value from the manifest.
Use breakpoint variants
Append @<breakpoint> to a utility when that declaration should start at a viewport threshold.
<h1 class="font:2xl font:3xl@md">Build for the current viewport</h1>Generated CSS
@layer theme { :root { --font-size-2xl: 1.5rem; --font-size-3xl: 2rem }}@layer utilities { .font\:2xl { font-size: var(--font-size-2xl) } @media (width>=64rem) { .font\:3xl\@md { font-size: var(--font-size-3xl) } }}Unqualified classes are the base state. Breakpoint variants layer changes on top, which makes the default mental model mobile-first without forcing every product to design only for phones.
Breakpoint scale
Use the scale as design vocabulary, not as device names. A token such as md should mean "the medium page layout starts here", not "iPad" or "desktop".
| Variant | Value | Generated query |
|---|---|---|
@4xs | 360px / 22.5rem | @media (width>=22.5rem) |
@3xs | 480px / 30rem | @media (width>=30rem) |
@2xs | 600px / 37.5rem | @media (width>=37.5rem) |
@xs | 768px / 48rem | @media (width>=48rem) |
@sm | 834px / 52.125rem | @media (width>=52.125rem) |
@md | 1024px / 64rem | @media (width>=64rem) |
@lg | 1280px / 80rem | @media (width>=80rem) |
@xl | 1440px / 90rem | @media (width>=90rem) |
@2xl | 1600px / 100rem | @media (width>=100rem) |
@3xl | 1920px / 120rem | @media (width>=120rem) |
@4xl | 2560px / 160rem | @media (width>=160rem) |
The exact values can differ by product. The important part is that the tokens stay semantically consistent: smaller tokens unlock compact layout changes, larger tokens unlock wider page structures.
Manifest changes around decisions
A breakpoint should exist because something meaningful changes. Avoid adding thresholds only because a popular device width exists.
| Decision | Good breakpoint use | Better handled elsewhere |
|---|---|---|
| Navigation | Switch from bottom tabs to top navigation | A single card changing layout inside a sidebar |
| App shell | Add a persistent sidebar at @md | Button padding that only belongs to one component |
| Page grid | Move from 4 columns to 8 or 12 columns | A gallery that depends on its rendered container |
| Typography | Increase heading scale when line length and hierarchy need it | Local text measure such as max-w:72ch |
| Density | Increase section rhythm and outer margins | Hard-coded spacing values repeated in markup |
<section class="grid-cols:4 grid-cols:8@sm grid-cols:12@md gap:md gap:lg@md"> ...</section>Generated CSS
@layer theme { :root { --spacing-md: 1rem; --spacing-lg: 1.5rem }}@layer utilities { .gap\:md { gap: var(--spacing-md) } .grid-cols\:4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) } @media (width>=52.125rem) { .grid-cols\:8\@sm { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)) } } @media (width>=64rem) { .gap\:lg\@md { gap: var(--spacing-lg) } } @media (width>=64rem) { .grid-cols\:12\@md { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)) } }}Query viewport ranges
Use comparison and logical operators when a style belongs to a range instead of every larger viewport.
<aside class="hidden@sm&<=md">...</aside>Generated CSS
@layer utilities { @media (width>=52.125rem) and (width<=64rem) { .hidden\@sm\&\<\=md { display: none } }}Ranges should be rare. If a rule appears at one size, disappears, and returns later, check whether the component is really responding to its container or whether the layout hierarchy should change.
Pair with container width caps
Viewport breakpoints decide when the page changes. Container size values decide how wide a wrapper may grow. Keep those roles separate.
<main class="w:full max-w:4xl@sm max-w:5xl@md max-w:7xl@lg mx:auto px:md px:xl@md"> ...</main>Here @sm, @md, and @lg come from the breakpoint namespace. The 4xl, 5xl, and 7xl width values come from the container namespace.
Prefer stable breakpoint habits
Breakpoints are named after devices.
@theme { --breakpoint-iphone: 24.375rem; --breakpoint-ipad: 51.25rem;}Breakpoints are named after layout thresholds.
@theme { --breakpoint-xs: 40rem; --breakpoint-sm: 48rem; --breakpoint-md: 64rem;}A reusable card responds to the viewport, so it breaks when placed in a narrow sidebar.
<article class="grid-cols:2@md">...</article>Page structure uses breakpoints, while reusable components use container queries.
<main class="grid-cols:12@md"> <section class="container"> <article class="grid-cols:2@container(md)">...</article> </section></main>Use breakpoints sparingly, name them for layout meaning, and keep component-local responsiveness in containers.