ITCSS
ITCSS — Inverted Triangle CSS, created by Harry Roberts — is not a naming convention like BEM and not a set of style categories like SMACSS. It's a rule for the import order of your stylesheets: organize your CSS files from broad, low-specificity, far-reaching rules at the top, down to narrow, high-specificity, limited-reach rules at the bottom. The name comes from drawing that order as a triangle — wide at the top, narrow at the bottom — inverted from how most people intuitively picture "big to small."
The layer order
Layer | Contains | Specificity / reach |
|---|---|---|
Settings | Variables and design tokens — colors, spacing scales, breakpoints | None (no actual CSS output) |
Tools | Mixins and functions (Sass, PostCSS) — no output either | None |
Generic | Resets and normalize — very low-specificity, far-reaching rules | Lowest |
Elements | Bare element selectors with no class — h1, a, table | Very low |
Objects | Layout-agnostic structural patterns — OOCSS-style objects, grid systems | Low |
Components | Specific, discrete UI components — the bulk of most projects | Medium |
Utilities | Single-purpose overrides, often with !important — the last word | Highest |
Why import order matters
Two rules with equal specificity resolve by source order — whichever is declared later in the cascade wins. ITCSS uses that fact deliberately: because generic resets are imported first and utilities are imported last, a utility class reliably beats a component class of equal or even slightly higher specificity, simply because it comes later in the file. This removes the temptation to win that fight by adding extra classes, upping specificity, or reaching for
!important — the ordering itself does the work.CSS
/* main.css — imports listed low-specificity/broad first, high-specificity/narrow last */ @import 'settings/colors'; @import 'settings/spacing'; @import 'generic/reset'; @import 'elements/headings'; @import 'elements/links'; @import 'objects/media'; @import 'objects/grid'; @import 'components/card'; @import 'components/nav'; @import 'utilities/spacing'; @import 'utilities/visibility';
CSS
/* components/card.css */
.card {
margin-bottom: 1rem;
}
/* utilities/spacing.css — imported LAST, so this reliably wins */
.mb-0 {
margin-bottom: 0;
}
/* <div class="card mb-0"> now has margin-bottom: 0 — no !important needed,
the utility wins purely because it's declared later in import order */ITCSS depends entirely on discipline in import order — nothing enforces it automatically
If someone adds a new component stylesheet and imports it after the utilities layer by mistake, that component's rules will now unexpectedly beat utility classes, silently reintroducing the exact specificity wars ITCSS exists to prevent. Getting the benefit requires everyone on the team to respect and maintain the ordering convention.
Cascade Layers make this ordering explicit instead of convention-based
Native Cascade Layers (@layer) let you declare the exact same broad-to-narrow priority ITCSS describes —
@layer generic, elements, objects, components, utilities; — and have the browser enforce that order regardless of where each rule physically sits in the file or how specific its selector is. ITCSS achieves its ordering by convention and file arrangement; cascade layers achieve the same intent with an actual browser guarantee.Next
See how large component-based apps solve CSS's global-scope problem more directly: Component-Scoped CSS.