CSS & Modern Layout — Intermediate
Responsive Design & Mobile-First Media Queries
A media query applies a block of CSS conditionally, based on the viewport (or device) matching certain conditions — most commonly a minimum or maximum width. The mobile-first approach writes base styles for the smallest/simplest case first, then layers min-width queries upward to add complexity as the viewport grows:
Mobile-first (min-width, layering up) is generally preferred over desktop-first (max-width, layering down) because the base case — no media query matched — is the most constrained, simplest layout, which also happens to be the right default for the widest range of real devices and slow connections. A desktop-first stylesheet ships its heaviest, most complex layout as the unconditional default, then overrides it downward for mobile — backwards from how most real traffic actually breaks down today.
Responsive Units
rem is the safer default for spacing and typography specifically because it's anchored to the root element's font-size regardless of nesting depth — an em value compounds with every nested element that also sets its own font-size, which is exactly the mechanism behind a confusing class of "why is this padding bigger than I set it to be" bugs.
CSS Custom Properties (Variables)
Custom properties are real, runtime CSS values — the browser resolves them live, they cascade and inherit like any other property, and they can be overridden at any level of specificity, including inside a media query or a pseudo-class:
This is fundamentally different from a Sass variable, which is substituted once at compile time and doesn't exist at all in the shipped CSS — a custom property is a genuine runtime value, which is exactly why it's the right tool for a theme toggle or anything JavaScript needs to read or write (element.style.setProperty('--brand-color', '#f00')).
Transitions & Animations
Transitions animate a property's change between two states (usually triggered by a state change like :hover or a class toggle):
Animations (@keyframes) define multi-step motion independent of a state trigger, useful for anything looping or with more than two states:
A real performance rule worth internalizing early: animating transform and opacity is cheap (the browser can often handle it on the compositor thread, without re-running layout), while animating width, height, top/left, or margin forces layout recalculation on every frame — genuinely visible as jank on lower-end devices. Prefer transform: translateX(...) over animating left for exactly this reason.
Media Query Best Practices
Try it: add @media (prefers-reduced-motion: reduce) to a page with a CSS animation, then toggle "Reduce motion" in your OS accessibility settings and reload — confirm the animation actually stops. This is a real, testable accessibility requirement, not a theoretical one.

