Frontend / CSS / 04_modern_css_and_perf.md

Logical Properties, Modern CSS, and Performance Hints

Updated 5 interview angles 5 min read source
On this page11
  1. What are logical properties and why use them?
  2. What does aspect-ratio do?
  3. How does scroll-snap work?
  4. What are content-visibility and contain?
  5. When should you use will-change?
  6. How do you implement dark mode in modern CSS?
  7. What is prefers-reduced-motion and why honor it?
  8. Gotchas
  9. Related
  10. Further reading
  11. Interview angle

Logical Properties, Modern CSS, and Performance Hints

A grab-bag of modern CSS that comes up at senior level: logical properties (margin-inline, inset-block-start) that adapt to writing direction (RTL/vertical) for free; aspect-ratio to reserve space (CLS); scroll-snap for carousels; and the performance levers — content-visibility (skip rendering offscreen content), contain (isolate a subtree), and will-change (promote to a layer, used sparingly). Plus the two preference-driven features every senior wires up: dark mode (prefers-color-scheme + color-scheme) and prefers-reduced-motion.

What are logical properties and why use them?

Flow-relative equivalents of physical properties — they follow the writing direction instead of fixed sides:

Physical Logical
margin-left/right margin-inline-start/end (or margin-inline)
margin-top/bottom margin-block-start/end (or margin-block)
top/left (inset) inset-block-start / inset-inline-start
width/height inline-size / block-size
border-top-left-radius border-start-start-radius

In an RTL locale, margin-inline-start automatically becomes the right side — so one stylesheet works for LTR and RTL without flipping. Essential for internationalized apps; good default even for LTR-only.

What does aspect-ratio do?

Sizes a box to a ratio so space is reserved before content loads — preventing layout shift (CLS):

css
.video { aspect-ratio: 16 / 9; width: 100%; }   /* height derived; no jump when the iframe loads */
img { aspect-ratio: 3 / 2; width: 100%; height: auto; }

Pair with width/height attributes on <img> for the best result (Responsive Images — srcset, sizes, <picture>).

How does scroll-snap work?

Declarative snapping for carousels/galleries — no JS:

css
.carousel { scroll-snap-type: x mandatory; overflow-x: auto; display: flex; }
.slide    { scroll-snap-align: start; flex: 0 0 100%; }

mandatory always snaps; proximity snaps only when close. scroll-driven animations (animation-timeline: view()/scroll()) extend this to tie animation progress to scroll position, also without JS.

What are content-visibility and contain?

Performance hints that limit how much the browser renders:

  • content-visibility: auto — skips rendering (layout/paint) of offscreen elements until they’re near the viewport, with contain-intrinsic-size to reserve approximate space. Massive win for long lists/articles — the browser does layout only for what’s visible.
    css
    .post { content-visibility: auto; contain-intrinsic-size: auto 500px; }
  • contain: layout/paint/size/style — promises the browser a subtree is independent, so changes inside don’t reflow/repaint the rest. contain: content is a common bundle. Reduces the scope of layout work.

Both improve rendering performance on large pages — see Frontend Performance — Senior Interview Prep.

When should you use will-change?

Sparingly. will-change: transform hints the browser to promote an element to its own compositor layer before an animation, avoiding a first-frame jank. But it costs memory, creates a stacking context, and overuse (or leaving it on permanently) hurts performance. Apply it just before animating and remove it after; never put will-change on many elements “to be safe.” Prefer animating only transform/opacity (compositor-only, no layout/paint).

How do you implement dark mode in modern CSS?

CSS variables + prefers-color-scheme, with color-scheme so form controls/scrollbars adapt too:

css
:root { color-scheme: light dark; --bg: white; --fg: #111; }
@media (prefers-color-scheme: dark) { :root { --bg: #0b0b0b; --fg: #f5f5f5; } }
[data-theme="dark"] { --bg: #0b0b0b; --fg: #f5f5f5; }   /* explicit override */
body { background: var(--bg); color: var(--fg); }

Default from the OS preference, allow an explicit toggle to override, and set color-scheme so native UI (inputs, scrollbars) matches. Token details: Design Tokens and Theming at Scale.

What is prefers-reduced-motion and why honor it?

A media query for users who’ve asked the OS to reduce motion (vestibular disorders, distraction). Gate non-essential animation behind it (WCAG 2.3.3):

css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

Reduce or remove large transforms/parallax; keep essential motion subtle.

Gotchas

  • content-visibility: auto without contain-intrinsic-size makes the scrollbar jump as elements render — always provide an intrinsic size estimate.
  • will-change left on permanently is a known anti-pattern — wastes memory and can reduce performance; add/remove around the animation.
  • Animating width/height/top/left triggers layout every frame (jank); animate transform/opacity instead.
  • Mixing logical and physical properties for the same side can conflict; commit to logical for i18n.
  • Dark mode flash (FOUC) — set the theme before first paint via an inline script; don’t wait for React hydration (Rendering Modes — Senior Interview Prep).
  • aspect-ratio with explicit height — if both are set and conflict, height wins and the ratio is ignored; let one dimension be derived.

Further reading

Interview angle 5

  • “How do you support RTL without a second stylesheet?” - logical properties. margin-inline-start and inset-block-start are defined relative to the writing direction, so the same rules flip automatically. Physical left/right is what forces the duplicate stylesheet.
  • “A long page scrolls badly. What can CSS do?” - content-visibility: auto skips layout, paint and style for offscreen subtrees, which is usually the largest single win. Pair it with contain-intrinsic-size so the skipped content still reserves height, or the scrollbar jumps as sections come into view.
  • “Which properties are cheap to animate, and why?” - transform and opacity, because they can be handled by the compositor without layout or paint. Animating width, top or margin re-runs layout every frame, which is what drops frames on a mid-range phone.
    • Follow-up: “Does will-change make things faster?” - only as a temporary hint before an animation starts. Left on permanently it promotes elements to their own layers, costs memory, and can make the page slower - which is the opposite of what people add it for.
  • “How do you implement dark mode without a flash?” - CSS custom properties for the palette, prefers-color-scheme for the default, color-scheme so form controls and scrollbars follow, and a tiny synchronous script before first paint to apply a stored preference. The flash is always a stored preference applied too late.
  • “What is the accessibility rule people forget?” - prefers-reduced-motion. Large transitions and parallax cause genuine nausea for some users, and honouring the query is one media block rather than a redesign.