ITCSS
itcss itcss (inverted triangle css) by harry roberts orders css in increasing specificity — settings, tools, generic, elements, objects, components,
Introduction
ITCSS (Inverted Triangle CSS) by Harry Roberts orders CSS in increasing specificity — Settings, Tools, Generic, Elements, Objects, Components, Utilities — forming an inverted triangle: many broad low-specificity rules at top, few narrow high-specificity utilities at bottom. Staff engineers adopt ITCSS when SMACSS categories need a strict import order and specificity ceiling.
The inverted triangle is a governance tool — utilities at the tip are the escape hatch, not the default authoring mode.
Business problem
Business pressure: Teams add !important when they cannot predict cascade order in a 50-file SCSS tree. ITCSS makes order physical — wrong-layer imports fail review. Specificity stays low until the utilities layer intentionally spikes.
- Predictability: Component styles beat objects; utilities beat components when needed.
- Onboarding: File path reveals specificity tier —
07-utilities/spacing.css. - Migration: Legacy CSS can be quarantined in a lower layer while new work uses components.
Why this feature exists
Platform history: Roberts (csswizardry.com) formalized ITCSS from consulting on large UK e-commerce CSS rebuilds where BEM alone did not fix import chaos.
- Problem solved: Uncontrolled specificity growth across partials.
- Rejected alternative: Single increasing-specificity file — unmaintainable at 10k lines.
- Modern role: Maps to @layer and monorepo CSS package ordering.
Browser rendering perspective
Rendering impact: Layer order reduces reliance on !important — fewer cascade surprises mean fewer forced recalculations from late-applied overrides.
- @layer: ITCSS layers can map 1:1 to CSS cascade layers in modern browsers.
Internal browser workflow
Import order (never reversed):
- Settings: variables, tokens — no output.
- Tools: mixins, functions — no output.
- Generic: reset, normalize.
- Elements: bare HTML —
a { }. - Objects: OOCSS patterns —
.o-media. - Components: UI chunks —
.c-card. - Utilities: trump layer —
.u-hidden.
Feature deep dive
Inverted triangle — width = number of rules; height = specificity.
/* 01-settings */ --color-primary: #4f46e5;/* 02-tools */ @mixin focus-ring { … }/* 03-generic */ *, *::before, *::after { box-sizing: border-box; }/* 04-elements */ h1 { font-size: 2rem; }/* 05-objects */ .o-media { display: flex; }/* 06-components */ .c-btn { padding: 0.5rem 1rem; }/* 07-utilities */ .u-mt-4 { margin-top: 1rem; }
Syntax
Prefixes: Objects o-, components c-, utilities u- — optional but aids grep. Settings/tools produce no CSS.
Examples
main.scss import chain:
@use 'settings/tokens';@use 'tools/mixins';@use 'generic/reset';@use 'elements/typography';@use 'objects/media';@use 'components/card';@use 'utilities/spacing';
Real-world use
ITCSS is widely taught in UK agency and enterprise circles. Many Sass architectures at Sky, BBC internal tools, and Shopify-era themes used numbered folders. Tailwind's @layer base/components/utilities parallels ITCSS generic/elements vs utilities.
Real production example
Pattern: Vite/PostCSS entry imports numbered partials; stylelint enforces no utility in components layer.
- Bundle: Purge scans only components + utilities layers for route-level CSS.
Enterprise use case
Enterprise: Design system ships layers as separate npm packages — consumers import full stack or subset.
- Carbon: SCSS partial ordering mirrors layered architecture.
Accessibility considerations
A11y: Utilities like .u-hidden-visually belong in utilities layer — one implementation, documented for screen-reader-only text.
Performance considerations
Performance: Utilities layer can bloat bundle — purge and limit utility generation to design token scale.
SEO considerations
SEO: Generic reset must not remove semantic defaults crawlers expect — use modern normalize, not aggressive reset.
Scalability considerations
Scale: Cross-layer imports forbidden — components cannot @use tools that emit CSS into wrong layer.
Common production issues
Failures: Utilities used for every spacing decision — triangle bottom becomes entire stylesheet.
Debugging guide
Debug: Check import order in built CSS — winning rule's layer position explains override.
Best practices
- Number folders 01–07 — order visible in IDE.
- One trump layer — utilities only.
- Map to @layer in modern builds.
- Quarantine legacy in separate import after components.
Anti-patterns
- Component file importing utilities into component selectors.
- !important in components layer — fix layer order instead.
Trade-offs
- Benefit: predictable cascade, grep-friendly structure.
- Cost: rigid import discipline; debate on object vs component.
Architecture review questions
- Where does a design-token-only file live?
- Can components @extend objects — layer implications?
- How does @layer map to our ITCSS folders?
Interview questions
Draw the ITCSS inverted triangle and list layers.(Intermediate)
Settings, Tools, Generic, Elements, Objects, Components, Utilities — specificity increases downward; rule count decreases. Utilities are narrow high-specificity trump cards.
Follow-up: What goes in objects vs components?
Hands-on exercise
Exercise: Reorganize project CSS into ITCSS folders. Map to @layer.
Staff engineer notes
- ITCSS is import order as architecture — without enforced imports, it's just folder names.
Common pitfalls
- Skipping objects layer — components duplicate OOCSS patterns.
Try it yourself
Edit the CSS panel — the preview updates live. Use DevTools Performance and Accessibility panels to validate.
Try it yourself
Summary
ITCSS enforces layered CSS architecture with explicit specificity growth — the inverted triangle governs import order and override predictability at enterprise scale.
Key takeaways
- ITCSS orders CSS by increasing specificity in an inverted triangle.
- Settings/tools emit no CSS; utilities trump components.