How a frontend team scales styling across thousands of components without losing its mind. Utility-first, scoped CSS, design tokens — every approach has a vocal fan club.
← Back to Client Side:has(), nesting, cascade layers) eliminates many old reasons to reach for preprocessors.| Approach | Examples | One-line summary |
|---|---|---|
| Utility-first | Tailwind CSS, UnoCSS, Windi | Compose UI from atomic classes; no naming. |
| CSS Modules | CSS Modules, Vue scoped <style>, Svelte scoped <style> | Local-by-default class names, no globals. |
| Preprocessors | Sass, Less, Stylus | Variables, nesting, mixins — predates modern CSS but still everywhere. |
| CSS-in-JS | styled-components, Emotion, vanilla-extract, Linaria | Write styles in JS/TS; per-component, dynamic. |
| Atomic / Functional | Tailwind, Tachyons, ACSS | Generate one class per CSS declaration. |
| Design systems | Material 3, Apple HIG, Carbon, Spectrum | Curated tokens + components. |
| Reset / Normalize | Normalize.css, modern-css-reset, Tailwind Preflight | Smooth out browser defaults. |
| Post-processors | PostCSS, Lightning CSS, Autoprefixer | Vendor prefixes, modern syntax → old, optimizations. |
Class names are the styles. No CSS files for components.
<button class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> Save </button>
tailwind.config.js.Class names get hashed at build time, so .button in two files won't collide.
/* Button.module.css */ .primary { background: #0066cc; } // Button.tsx import styles from './Button.module.css'; <button className={styles.primary}>Save</button>
Vue and Svelte ship the same idea in their <style scoped> blocks.
Variables, nesting, mixins, partials, math. Most modern CSS now supports nesting natively, but Sass still wins on:
Writing styles in JS gave per-component scope and dynamic theming, but classic runtime libraries (styled-components, Emotion) inject styles at runtime — slower and incompatible with React Server Components.
style for those today.Named values (color, spacing, font-size) defined once, consumed everywhere — usually as CSS variables or in a token JSON consumed by Tailwind / Style Dictionary / Tokens Studio.
:root {
--color-primary: #065A82;
--space-md: 1rem;
--radius-md: 8px;
}
Tailwind v4 + a small set of design tokens.
CSS Modules or vanilla-extract — predictable, framework-agnostic.
CSS custom properties + a token pipeline (Style Dictionary).
Plain modern CSS is enough — actually.