Topic 14 / 14

CSS Architecture & Best Practices

~10 min read  //  CSS Series  //  Coding India

The Real Problem: CSS at Scale

CSS is easy to write and hard to maintain. Global scope means any rule can affect anything; without conventions, stylesheets become append-only — nobody dares delete a rule. Architecture is how teams keep CSS deletable.

Naming: BEM

Block, Element, Modifier — boring, explicit, and effective:

/* Block — the component */
.card { }

/* Element — a part of it (double underscore) */
.card__title { }
.card__thumb { }

/* Modifier — a variant (double hyphen) */
.card--featured { }
.card__title--large { }
<article class="card card--featured">
  <img class="card__thumb" src="…" alt="">
  <h3 class="card__title">Django Tutorial</h3>
</article>

Every selector is one class deep — flat specificity, zero collisions, and you can tell what any class is from its name alone.

Utilities for the Gaps

A few single-purpose helpers complement components nicely:

.visually-hidden {       /* accessible hiding — screen readers still read it */
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.text-center { text-align: center; }
.mt-2 { margin-top: 0.5rem; }

(Tailwind takes this idea to its logical extreme — utility-only styling. Whichever side you pick, the underlying CSS knowledge from this series is what makes you effective.)

File Organisation

styles/
├── tokens.css        /* :root custom properties */
├── reset.css
├── base.css          /* element defaults: body, a, headings */
├── layout.css        /* page scaffolding, grids */
├── components/
│   ├── card.css
│   ├── button.css
│   └── nav.css
└── utilities.css

@layer — Cascade Control

Declare layer order once; later layers always beat earlier ones regardless of specificity:

@layer reset, base, components, utilities;

@layer components {
  .card { padding: 2rem; }
}
@layer utilities {
  .p-0 { padding: 0; }    /* wins over .card despite equal specificity */
}

Layers end the specificity arms race structurally — utilities always win, resets always lose, by design.

Accessibility Is CSS’s Job Too

  • Visible :focus-visible styles on everything interactive.
  • Contrast ≥ 4.5:1 for body text (DevTools shows the ratio).
  • Honor prefers-reduced-motion and prefers-color-scheme.
  • Don’t communicate by colour alone — pair it with icons or text.
  • Minimum 44×44px touch targets on mobile.

Production Checklist

  • Design tokens in custom properties; components consume tokens only.
  • Flat, class-based selectors (BEM or equivalent); no IDs, minimal nesting.
  • Mobile-first media queries; container queries for reusable components.
  • Animate only transform/opacity; respect reduced motion.
  • box-sizing: border-box globally; a consistent spacing scale.
  • Test at every width by dragging, not just at breakpoints.

You now hold the complete modern CSS toolkit — selectors through architecture. Pair this with the JavaScript series to make interfaces behave, and the React series to compose them into applications. The fastest way to internalise CSS: rebuild a site you admire, from a blank file, without looking at its source until you’re stuck.