Contents

Frontend Development › CSS

CSS Architecture

Organizing styles so a large codebase stays maintainable.

Also known as: CSS organization, CSS methodology, scalable CSS, BEM architecture, CSS at scale

CSS is global by default, and every rule can affect any element. In a small site that’s fine. In a large codebase with many people, it leads to the familiar mess: specificity wars, !important everywhere, styles that can’t be deleted because nobody knows what uses them, and changes that break unrelated pages. CSS architecture is how you organize styles so the codebase stays maintainable as it grows.

The problems an architecture solves

  • Global scope: a generic .title in one place affects another.
  • Specificity conflicts: ever-stronger selectors fighting each other (specificity).
  • Order dependence: results change depending on which stylesheet loads last.
  • Dead code: unused rules that nobody dares to remove.
  • Inconsistency: ten slightly different blues and nine spacing values (design tokens).
  • Unclear ownership: where do I put this style?

Approaches

ApproachIdea
Naming conventions (BEM)Name classes predictably (card__title--large), so they’re unique, flat and low-specificity
Scoped styles (CSS Modules, component-scoped styles in frameworks)Styles are local to a component by construction, with generated unique class names
Utility-first CSS (utility-first CSS)Compose small single-purpose classes (p-4 flex gap-2) in markup, with no custom CSS growth
CSS-in-JS (CSS-in-JS)Styles written in JavaScript alongside components, with scoping and dynamic values
Cascade layers (layers)Declare explicit priority between groups (reset, base, components, utilities), regardless of selector specificity
Design tokens and variables (CSS variables)One source for colors, spacing and type

They aren’t mutually exclusive. A project might use tokens, layers, scoped component styles and a few utilities.

Principles that hold across approaches

  • Keep specificity low and flat. Style with single classes. No IDs, no deep nesting, and !important only in deliberate utility cases.
  • Scope by component, so deleting a component deletes its styles.
  • Separate concerns: base/reset, layout, components, utilities, themes.
  • Use tokens instead of raw values.
  • Make layout the parent’s job. A component shouldn’t set its own outer margin. Callers control spacing.
  • Prefer composition to overriding. Provide variants and props rather than letting callers hack styles.
  • Be consistent and document the convention. Enforce with linting (linters).
  • Plan for theming (dark mode, brands) through tokens.
  • Watch performance: CSS size, runtime cost of CSS-in-JS, unused CSS.

Choosing

Match it to your stack and team: a component framework often suggests scoped styles, and a design-system-heavy team may like utilities plus tokens. The wrong choice is no deliberate choice, where each developer invents their own approach. Pick one, write it down and keep it consistent (following conventions).