2025-12-29

The "Atomic" Hack: Scale Your Entire Website UI with 5 Lines of CSS

Web Dev, CSS, Design Systems · Dorian Sotpyrc

A UI scale knob controlling typography, spacing, and radius across a website
One knob, many outcomes: change a single scale value and your UI stays proportional.

The problem: “global tweaks” don’t stay global

I used to treat “global” CSS changes like harmless housekeeping. Bump the base font-size. Nudge spacing. Round corners a bit more. Then I’d refresh the site and immediately feel it: buttons got chunky, cards got cramped, modals looked like they shipped from a different product.

The frustrating part is the drift. Typography, spacing, radius, and shadows are supposed to feel like they belong to the same system— but we often change them independently. A font change doesn’t automatically rebalance padding. New radii don’t automatically harmonize with shadows. And the hidden cost is always the same: manual retuning across dozens of components.

Why components drift out of proportion

  • Font-size changes break the relationship between text and the spacing around it.
  • Mobile and desktop need different “density,” but most components hardcode one set of numbers.
  • Your design “feel” becomes fragile: small tweaks cause big inconsistency.

The Atomic Hack in one sentence

Set one scale variable (--ui-scale), derive a tiny token set from it (space/type/radius/shadow), and make components consume tokens—not raw numbers.

One scale variable

  • You change --ui-scale once.
  • Everything else is computed with calc().
  • Components stay proportional because they all reference the same source of truth.

The ~5 lines of CSS (core snippet)

This is the core. It’s intentionally small. You can expand later, but you don’t need a “design system rewrite” to start.

CSS
:root{
  --ui-scale: 1;                 /* one knob */
  --space:  calc(1rem * var(--ui-scale));
  --text:   calc(1rem * var(--ui-scale));
  --radius: calc(.75rem * var(--ui-scale));
  --shadow: 0 calc(8px * var(--ui-scale)) calc(24px * var(--ui-scale)) rgb(0 0 0 / .12);
}

That’s the hack: one variable drives multiple “token families.” When you tighten the scale, your type gets slightly smaller, your padding gets tighter, your corners get subtly sharper, and your shadows don’t suddenly feel too heavy.

Make it fluid: clamp() for scale that follows the viewport

You can keep --ui-scale fixed per breakpoint. Or you can let it move smoothly with the viewport while staying in a safe range. This is the pattern I reach for when I want the UI to breathe on larger screens without redesigning anything.

A safe clamp() pattern

CSS
:root{
  --ui-scale: clamp(.92, .85 + .3vw, 1.08);
}

What to clamp (and what not to)

  • Clamp the scale. The min prevents tiny UI on small phones; the max prevents comically large UI.
  • Watch line length. Fluid type can push paragraphs into “too wide to read” territory if the layout also expands.
  • Don’t blindly scale everything. Some things (like hairline borders) shouldn’t grow 1:1 forever.
Clamp() scale curve (concept)
Scale curve Clamp rails (min/max)
0.92 0.96 1.00 1.04 1.08 320px 1024px 1920px viewport width --ui-scale

Apply tokens everywhere (without rewriting your CSS)

The migration trick is: don’t convert the whole codebase. Pick 2–3 “surface” components you touch constantly. Once they’re token-based, everything else can move over gradually.

Start with 3 surfaces

  • Buttons: padding + font-size + radius.
  • Cards: padding + gap + radius + shadow.
  • Forms/modals: spacing hierarchy (header/body/footer) so density changes feel intentional.

Minimal example: components consuming the derived tokens.

CSS
/* components */
.btn{
  font-size: var(--text);
  padding: calc(.6 * var(--space)) calc(1.0 * var(--space));
  border-radius: var(--radius);
}

.card{
  padding: calc(1.25 * var(--space));
  border-radius: calc(1.1 * var(--radius));
  box-shadow: var(--shadow);
}

Common failure modes (and quick fixes)

The “everything scales, including the wrong things” issue

  • Borders: don’t scale hairlines forever. Consider pinning borders to 1px (or a narrow range) even when the UI grows.
  • Headings: cap big display sizes. It’s fine for body text + spacing to scale, while h1 growth is limited.
  • Shadows: scaling blur/spread is good, but keep opacity stable (or it can look “muddy” at large sizes).

Quick checklist

Checklist: implement in order
Step What you change What you verify
Tokenize Space / type / radius first Components reference var(--space), var(--text), var(--radius)
Migrate Replace raw px in 3 key components UI stays consistent at --ui-scale: .92 and 1.06
Scale strategy Add clamp() or 2 breakpoints No tiny UI on phones; no huge UI on wide monitors
Sanity test Phone, laptop, large display Tap targets, heading rhythm, paragraph readability

Related PLEX reading

References & further reading