Design Foundations

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.

TokenValuePXDescription
--breakpoint-4xs22.5rem360pxSmall phone and compact embedded surfaces.
--breakpoint-3xs30rem480pxLarge phone or narrow split-pane entry point.
--breakpoint-2xs37.5rem600pxSmall tablet, large modal, and compact app shell width.
--breakpoint-xs48rem768pxTablet portrait or roomy mobile layout.
--breakpoint-sm52.125rem834pxTablet landscape and small desktop layout.
--breakpoint-md64rem1024pxDefault desktop shell threshold.
--breakpoint-lg80rem1280pxWide desktop layout with stronger horizontal composition.
--breakpoint-xl90rem1440pxLarge desktop or high-density canvas.
--breakpoint-2xl100rem1600pxExpanded workstation viewport.
--breakpoint-3xl120rem1920pxVery wide product or editorial canvas.
--breakpoint-4xl160rem2560pxMaximum 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".

VariantValueGenerated query
@4xs360px / 22.5rem@media (width>=22.5rem)
@3xs480px / 30rem@media (width>=30rem)
@2xs600px / 37.5rem@media (width>=37.5rem)
@xs768px / 48rem@media (width>=48rem)
@sm834px / 52.125rem@media (width>=52.125rem)
@md1024px / 64rem@media (width>=64rem)
@lg1280px / 80rem@media (width>=80rem)
@xl1440px / 90rem@media (width>=90rem)
@2xl1600px / 100rem@media (width>=100rem)
@3xl1920px / 120rem@media (width>=120rem)
@4xl2560px / 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.

DecisionGood breakpoint useBetter handled elsewhere
NavigationSwitch from bottom tabs to top navigationA single card changing layout inside a sidebar
App shellAdd a persistent sidebar at @mdButton padding that only belongs to one component
Page gridMove from 4 columns to 8 or 12 columnsA gallery that depends on its rendered container
TypographyIncrease heading scale when line length and hierarchy need itLocal text measure such as max-w:72ch
DensityIncrease section rhythm and outer marginsHard-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.


  • Master UI


© 2026 Aoyue Design LLC.MIT License
Trademark Policy