CSS Architecture ITCSS Overview
ITCSS inverted triangle — settings through utilities — how layer order reduces specificity wars in large stylesheets.
- 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:
- Settings — variables, config (no CSS output, or only custom properties)
- Tools — mixins/functions (preprocessors)
- Generic — reset/normalize
- Elements — bare
h1,a,buttondefaults - Objects — non-cosmetic layout patterns (
.o-media, grid wrappers) - Components — UI chunks (
.c-card,.c-modal) - 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
- Putting one-off page CSS in
genericbecause “it’s global.” - Component files that re-declare reset-level margins.
- Utilities without a naming prefix — unreadable soup.
- Ignoring layers and relying only on import order in a bundler graph.
- 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.
Related
- Cascade layers @layer
- BEM naming methodology
- Utility-first CSS tradeoffs
- CSS reset vs normalize vs layer
Further reading
Related guides
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- Cascade Layers @layerUse @layer to order reset, base, components, and utilities so specificity wars lose — layer priority, unlayered CSS, and !important.
- Utility-First CSS TradeoffsUtility-first (Tailwind-style) pros and cons — speed, consistency, HTML noise, design-token discipline, and when components still win.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.