Responsive and interactive states
Use mobile-first responsive variants
Apply base utilities for small screens and layer changes at min-width breakpoints with sm, md, lg, xl, and 2xl variants.
Tailwind is mobile-first. Unprefixed utilities apply at every width. A breakpoint variant applies from that width upward.
<img class="w-16 md:w-32 lg:w-48" src="photo.jpg" alt="">
The image is w-16 on a phone. From md, which is 48rem or 768px, it becomes w-32. From lg, 64rem or 1024px, it becomes w-48. Each larger variant overrides the same property when its media query matches.
The default breakpoints are sm (40rem), md (48rem), lg (64rem), xl (80rem), and 2xl (96rem). All of them are min-width queries.
sm does not mean “phone”
This trips everyone up at first. sm: doesn’t target small screens. It targets the sm width and everything wider. To style phones, use the unprefixed classes. Then add complexity as space appears:
<section class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">...</section>
One column by default. Two from md. Three from lg. The base classes are the constrained layout, and the variants add to it.
Choose breakpoints from the content
Add a second column when two cards actually fit and stay readable, not because a device list says something is a “tablet”. Browser windows get resized, people use split screen, sidebars eat space, and zoom shrinks the effective viewport. Device labels are unreliable. Content widths are not.
Ranges
You can bound a variant with a maximum too, like md:max-lg:flex, which applies only between md and lg. Use this for a real need. A few cumulative rules are far easier to follow than many narrow ranges stacked on top of each other.
Hiding content has a cost
hidden md:block removes the element below md. Removed means gone: not visible, not focusable, not announced by a screen reader. That’s fine for a duplicate or something truly optional. It’s not fine for the only navigation, unless a replacement control exists at that width.
Test by resizing slowly
Three preset screenshots miss the interesting widths. Drag the window edge slowly and watch for the exact point where text wraps badly, controls collide, or reading order stops making sense. Zoom in too. At 200% zoom the CSS viewport is half as wide, so a 1440px monitor behaves like a 720px one and your compact layout should kick in.
Try this: build a one-column list that gains columns only when the cards stay readable. Write down the width where the content broke and justified each variant, and confirm no action disappears at 200% zoom.
Lesson completed