The usual way to pick breakpoints is to consult a list of devices: phone, tablet, laptop, desktop, with a representative width for each. There are two problems with that. The device list changes every year, and screen width no longer tells you what kind of device you are on.
Why device names go stale
A “tablet” is narrow held one way and wide held the other; a folding device crosses two of your bands on its own. A touchscreen laptop is wide but operated with fingers. Plenty of people run their browser at half the screen. You can know the width. You cannot know the device.
So the comment saying “iPad” next to @media (min-width: 768px) quietly stops being true, and the next person to trust it ends up adjusting a layout for a device that no longer exists.
Finding where it stops working
Ask the screen instead. Put one component in a browser, start very narrow, and widen slowly while watching for the moment it becomes uncomfortable. That width is your breakpoint.
The signals are fairly consistent: a line of body text long enough that your eye struggles to find the next one, a card title wrapping to four lines, table columns colliding, two buttons about to overlap. Any one of those is the place to change the layout.
Crucially, the value you find belongs to the component, not the page. The width at which a card grid breaks is not the width at which your navigation breaks. Force them into a single number and one of them is always early or late.
Fewer is better
If you have ended up with seven breakpoints, it usually means the states in between are not fluid. When type and spacing are re-declared at every step, any width slightly off a step looks wrong, and you patch that wrongness with another breakpoint. The next part tackles exactly this.
Use rem rather than px in the query. @media (min-width: 48rem) respects the browser’s base font setting, so a reader who has increased text size gets the layout change slightly earlier — which is correct, because larger text means fewer characters fit on a line.
One step further, container queries. Declare container-type: inline-size on a parent and the child can ask @container (min-width: 30rem) about the space it has actually been given. The same card goes horizontal in a wide article and vertical in a narrow sidebar, by itself — the most precise form of “the component owns its own breakpoint”.
Auditing and adjusting the breakpoints a theme already ships with is covered in the Themes & plugins archive, and front-end structure is part of the work in our optimization program.
Next part
The surest way to need fewer breakpoints is to make the space between them fluid. Next: joining type and spacing together with a single clamp().