Back to CSS
CSS
medium
mid

How do you make a web app responsive using media queries and relative units?

Fluid layouts (flex/grid + %), relative units (`rem`/`em`/`ch`/`vw`/`vh`), breakpoints via `@media (min-width)` (mobile-first), `clamp()` for fluid type, container queries for component-local responsiveness, `<picture>`/srcset for images, and a viewport meta tag. Layer with logical properties (`margin-inline`) for i18n/RTL.

4 min read·~10 min to think through

Responsiveness today is fluid by default, breakpoints for layout shifts, components query their own container — not just one fixed grid that snaps at 768px.

1. Viewport tag

html
<meta name="viewport" content="width=device-width, initial-scale=1">

Without it, mobile defaults to a ~980px layout. See [[why-does-the-viewport-meta-tag-matter-for-mobile-ui]].

2. Relative units

UnitWhen
remType, spacing scale (honors user font-size preference).
emComponent-local sizing relative to parent.
%Layout widths.
vw/vh / svh/dvhViewport-relative sizing; prefer dvh over vh on mobile.
chOptimal text measure (max-width: 65ch).
clamp(min, ideal, max)Fluid type / spacing.

clamp(1rem, 0.8rem + 1vw, 1.5rem) — type fluidly scales between bounds.

3. Mobile-first media queries

css
.card { padding: 1rem; }
@media (min-width: 48em) { .card { padding: 2rem; } }
@media (min-width: 80em) { .card { padding: 3rem; } }

Use em units in queries so user zoom shifts breakpoints consistently.

4. Container queries

css
.card-wrap { container-type: inline-size; }
@container (min-width: 30em) { .card { display: flex; } }

The component reacts to its own width, not the viewport — essential for design systems.

5. Layouts: flex + grid

  • Flex for one-axis (rows of items).
  • Grid for two-axis layouts (grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)) auto-wraps).

6. Responsive images

html
<img srcset="x-400.jpg 400w, x-800.jpg 800w" sizes="(min-width:48em) 50vw, 100vw" src="x-800.jpg">

Or <picture> with <source media> for art direction.

7. Logical properties

margin-inline, padding-block, inset-inline-start — work for LTR + RTL without flipping styles.

8. Touch / pointer

@media (hover: hover) { ... } for hover-only effects on devices that actually hover.

9. Density

@media (prefers-color-scheme: dark), (prefers-reduced-motion), (prefers-contrast: more) — respect user OS settings.

Interview framing

"Fluid layouts with flex/grid, relative units (rem for type, % and fr for layout, clamp for fluid scale), mobile-first @media (min-width) in em units, and container queries for component-local responsiveness. Responsive images via srcset/sizes. Logical properties for i18n. Respect user prefs (prefers-color-scheme, prefers-reduced-motion). And the viewport meta tag is non-negotiable."

Follow-up questions

  • Why prefer container queries over media queries for components?
  • When would you use vw vs %?
  • How do you handle responsive images for art direction?

Common mistakes

  • px breakpoints that ignore user zoom.
  • Forgetting the viewport meta tag.
  • Hardcoding heights with vh on mobile (mobile chrome shifts vh).

Performance considerations

  • Avoid heavy layout-shifting media queries on resize. Use container queries to scope work. Responsive images cut bytes massively.

Edge cases

  • iOS safe areas with notch — env(safe-area-inset-*).
  • Soft keyboard collapses viewport (visualViewport API).
  • RTL — logical properties or directional CSS.

Real-world examples

  • Every modern marketing site, Tailwind's mobile-first defaults, GitHub UI.

Senior engineer discussion

Seniors lead with container queries + logical properties + user-pref media features, not just `min-width`. They treat responsiveness as a first-class architecture concern, not retroactive CSS.

Related questions