ESC

Type to search the knowledge base.

CSS Architecture ITCSS Overview

ITCSS inverted triangle — settings through utilities — how layer order reduces specificity wars in large stylesheets.

advanced3 min read
  • css
  • architecture
  • itcss

ITCSS (Inverted Triangle CSS) is a file/layer ordering model: broad, low-specificity rules at the top; narrow, explicit rules at the bottom. Harry Roberts popularized it for large codebases where “just add a more specific selector” becomes institutional debt.

Docs/context: ITCSS overview articles, pair with modern @layer.

The triangle (bottom wins)

From generic → specific:

  1. Settings — variables, config (no CSS output, or only custom properties)
  2. Tools — mixins/functions (preprocessors)
  3. Generic — reset/normalize
  4. Elements — bare h1, a, button defaults
  5. Objects — non-cosmetic layout patterns (.o-media, grid wrappers)
  6. Components — UI chunks (.c-card, .c-modal)
  7. Utilities — single-purpose helpers (.u-hidden, .u-mt-2), highest priority
      settings
       tools
      generic
     elements
     objects
   components
    utilities   ← most explicit, should win

Mapping to cascade layers

@layer settings, generic, elements, objects, components, utilities;

@layer settings {
  :root {
    --space-1: 0.25rem;
    --color-text: #14212b;
  }
}

@layer generic {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }
}

@layer elements {
  body {
    margin: 0;
    font-family: system-ui, sans-serif;
    color: var(--color-text);
  }

  a {
    color: inherit;
  }
}

@layer objects {
  .o-cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3, 1rem);
  }
}

@layer components {
  .c-button {
    padding: 0.5rem 1rem;
    border-radius: 0.375rem;
    background: var(--brand, #0b6bcb);
    color: white;
  }
}

@layer utilities {
  .u-hidden {
    display: none !important; /* utilities often need a hammer */
  }

  .u-text-center {
    text-align: center;
  }
}

Whether you use ITCSS folder names or @layer names, the idea is the same: reach for a lower layer only when a higher one can’t express the need.

Objects vs components

  • Objects — structural, content-agnostic (media object, flag object, cover, stack).
  • Components — product meaning (pricing card, invoice table).
/* Object: reusable structure */
.o-stack > * + * {
  margin-block-start: var(--stack-space, 1rem);
}

/* Component: specific UI */
.c-invoice-summary {
  border: 1px solid var(--border);
  padding: 1rem;
}

Crossing the streams — putting one-off marketing spacing into a shared object — is how triangles collapse.

Why it still matters with modules and Tailwind

  • CSS modules scope class names but not global resets, tokens, or element defaults — you still need an order story.
  • Utility-first is ITCSS with almost everything in the utilities layer; design tokens + base still sit above.
  • Design systems publish components; apps need a higher utility/override layer without forking specificity.

Interview out-loud

“ITCSS orders styles from generic low-specificity rules to explicit utilities so overrides flow downward. I map it to @layer today: settings, generic, elements, objects, components, utilities. Components shouldn’t fight utilities; if they do, the layer order is wrong or the component is too opinionated.”

Footguns

  1. Putting one-off page CSS in generic because “it’s global.”
  2. Component files that re-declare reset-level margins.
  3. Utilities without a naming prefix — unreadable soup.
  4. Ignoring layers and relying only on import order in a bundler graph.
  5. Treating ITCSS as a religion when a small site needs three files.

Folder sketch teams actually use

styles/
  settings/_tokens.css
  generic/_reset.css
  elements/_typography.css
  objects/_stack.css
  objects/_cluster.css
  components/_button.css
  components/_card.css
  utilities/_display.css
  main.css   /* @import order + @layer order */

Import order should match the triangle. With bundlers, enforce layers in main.css even if tools concatenate files arbitrarily. Review PRs for “quick page CSS” dumped into generic — that is how the triangle collapses into soup within a quarter.

Further reading

Related guides