ITCSS: Scalable CSS Architecture for Large Projects
AI generated
{ }
@
CSS · Architecture · Scaling · Large Teams
ITCSS: Scalable CSS Architecture
seven layers by increasing specificity

ITCSS orders a stylesheet not by file type or component, but by the specificity and reach of every rule. This CSS architecture makes conflicts between global base rules and specific overrides predictable, instead of leaving them to the chance of import order, and stays maintainable across dozens of developers over years.

19 min read ITCSS · Cascade Layers · Specificity · Scaling CSS 2026 · Framework agnostic

1. The core problem: specificity without order

ITCSS stands for Inverted Triangle CSS and was developed by Harry Roberts as an answer to a problem most grown stylesheets share, namely specificity that grows chaotically rather than under control as a project ages. Without deliberate architecture, global base rules, component specific adjustments and exceptions for individual edge cases end up in the same file, or in arbitrarily sorted files whose order in the build process decides which rule wins, not the meaning of its content.

The core idea of ITCSS is deceptively simple: a stylesheet is organized into layers that run from generic and broad reaching to specific and explicit, visualized as an inverted triangle. At the very top, the wide side of the triangle, sit rules with very low specificity and broad reach, such as CSS custom properties and reset rules. At the very bottom, the narrow tip, sit highly specific exception rules that are used deliberately and rarely. This CSS architecture turns the order of the stylesheet into a direct mapping of the specificity hierarchy, instead of an arbitrary history of commits.

The practical effect: a developer adding a new rule has to ask which layer it belongs to, not just which file happens to be open. This discipline, applied consistently across an entire project, prevents the typical specificity war where every new rule needs an even more specific one to win. ITCSS solves this problem not through prohibitions, but through a clear map of where every kind of rule belongs.

2. Settings and Tools: the invisible layers

The first layer in ITCSS is called Settings and contains exclusively variables, no actually rendered CSS rules. This is where custom properties for colors, spacing scales, breakpoints and typography values belong. This layer produces no CSS output in the sense of visible declarations by itself, it defines the vocabulary that all subsequent layers use. The benefit: a change to a base value, say the primary brand color, propagates automatically through the entire stylesheet without touching a single component rule.

The second layer, Tools, contains mixins and functions if a preprocessor like Sass is in use, or reusable custom property calculations with plain CSS. This layer also produces no direct output, it provides tools that later layers call. A common rule of thumb in ITCSS: if a layer compiles to empty CSS in isolation, it belongs to Settings or Tools, not to one of the following, output producing layers.


/* 1-settings/_colors.css — variables only, no rendered output */
:root {
  --color-brand-500: oklch(0.55 0.18 275);
  --color-brand-600: oklch(0.48 0.19 275);
  --color-surface: oklch(0.98 0.01 275);
  --space-unit: 0.25rem;
  --radius-md: 0.5rem;
}

/* 2-tools/_mixins.css — reusable helpers, still no direct output */
@custom-media --viewport-md (width >= 48rem);

/* Example Sass mixin equivalent, if a preprocessor is used:
@mixin focus-ring($color: var(--color-brand-500)) {
  outline: 2px solid $color;
  outline-offset: 2px;
}
*/

3. Generic and Elements: the global foundation

The third layer, Generic, is the first that actually produces CSS output. This is where reset and normalize rules, box sizing declarations, and broad reaching selectors like * or ::before, ::after belong. These rules affect the entire document equally and deliberately carry minimal specificity, so they can be overridden without friction by every following layer. In ITCSS it matters that this layer contains no class selectors, only type and universal selectors.

The fourth layer, Elements, styles bare HTML elements without any class: h1, a, table, input. This is the level where default typography and default behavior for unstyled content are defined, for example in a CMS generated article body where no classes are available. This CSS architecture ensures that even raw, unclassified HTML looks reasonable without requiring a single class.


/* 3-generic/_reset.css — broad reach, minimal specificity */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
}

/* 4-elements/_typography.css — bare HTML elements, no classes */
h1, h2, h3 {
  font-weight: 700;
  line-height: 1.2;
}

a {
  color: var(--color-brand-600);
  text-decoration-thickness: from-font;
}

table {
  border-collapse: collapse;
  width: 100%;
}

4. Objects: layout related, reusable patterns

The fifth layer, Objects, follows the OOCSS principle by Nicole Sullivan: purely structural, layout related classes without visual styling like color or typography. A typical example is a grid system or a media object pattern that defines structure (say, an image on the left, text on the right) but makes no statement about colors or font sizes. Naming conventions like a leading o- prefix, for example o-media, make it immediately obvious that a class belongs to the Objects layer and is purely structural in intent.

This layer is deliberately separated from Components in ITCSS because it pursues a different kind of reusability. An Objects pattern should work across entirely different visual contexts, a card, a comment, a product snippet can all use the same o-media structure without that structure saying anything about appearance. Anyone who breaks this separation and mixes colors directly into Objects classes loses exactly the reusability benefit this layer is meant to provide.


/* 5-objects/_media.css — structure only, no color, no typography */
.o-media {
  display: flex;
  align-items: flex-start;
  gap: var(--space-unit) * 4;
}

.o-media__figure {
  flex-shrink: 0;
}

.o-media__body {
  flex: 1 1 auto;
  min-width: 0; /* prevents flex overflow with long text */
}

/* Grid object, purely structural */
.o-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: calc(var(--space-unit) * 6);
}

5. Components: the actual UI layer

The sixth layer, Components, is where most day to day development work happens. This is where concrete, named UI building blocks live, like a button, a card or a navigation menu, typically marked with a c- prefix, for example c-button. Unlike Objects, Components carry full visual responsibility, color, typography, shadows and transitions belong here. This layer can internally use Objects, for example a card that uses the o-media pattern for its internal layout, but makes its own color and typography decisions.

In practice, Components is the layer most often combined with BEM or a similar naming convention, because this is where most named, self contained UI units originate. ITCSS makes no requirement about which naming convention is used within the Components layer, it only fixes where these rules sit in the specificity gradient, namely noticeably more specific than Generic and Objects, but below the last two layers.


/* 6-components/_button.css — full visual responsibility */
.c-button {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--space-unit) * 2);
  padding-block: calc(var(--space-unit) * 3);
  padding-inline: calc(var(--space-unit) * 5);
  border-radius: var(--radius-md);
  background: var(--color-brand-500);
  color: white;
  font-weight: 600;
  transition: background-color 150ms ease;
}

.c-button:hover {
  background: var(--color-brand-600);
}

.c-button--secondary {
  background: transparent;
  border: 1px solid var(--color-brand-500);
  color: var(--color-brand-600);
}

6. Trumps: deliberate, documented exceptions

The seventh and final layer, Trumps, is the most specific in the entire ITCSS system and contains utility classes and, in rare, documented cases, !important declarations. Classes like u-hidden or u-text-center belong here because they are meant to deliberately override every previous layer. The decisive difference from an arbitrary !important scattered somewhere in the code: in Trumps, the high specificity is intentional and concentrated in exactly one, clearly defined place in the stylesheet, instead of spread across the entire project.

A common mistake when starting with ITCSS is putting too many rules into Trumps, because it is the easiest way to solve a specificity problem in the short term. This CSS architecture only works, though, if Trumps stays small and rare, ideally a single digit number of utility classes for genuine, rare layout exceptions. If this layer grows uncontrolled, the whole system loses its benefit, because it once again becomes unclear which of the many highly specific rules wins in which context.


/* 7-trumps/_utilities.css — highest specificity, used sparingly and deliberately */
.u-hidden {
  display: none !important;
}

.u-visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
}

/* Deliberate, documented override for a rare edge case, not a habit */
.u-no-scroll {
  overflow: hidden !important;
}

7. Implementing ITCSS with native Cascade Layers

Since wide browser support for @layer, ITCSS can be enforced not only through file order but natively through CSS Cascade Layers. This solves a subtle problem of the classic ITCSS implementation: without Cascade Layers, the specificity order between layers still depends on the declaration order in the compiled stylesheet. A file imported in the wrong order by mistake can undermine the entire architecture without any error becoming visible, because CSS does not throw a warning for specificity problems.

With explicit layer declarations, the order of layers is guaranteed independent of file order. A layer declared later wins over a layer declared earlier, regardless of how specific the individual selectors within the layers are. This makes ITCSS more robust against build tool quirks and import order mistakes that, experience shows, eventually occur in large projects with many contributors.


/* Layer order is declared once, independent of file import order */
@layer settings, tools, generic, elements, objects, components, trumps;

@import url("./1-settings/colors.css") layer(settings);
@import url("./3-generic/reset.css") layer(generic);
@import url("./4-elements/typography.css") layer(elements);
@import url("./5-objects/media.css") layer(objects);
@import url("./6-components/button.css") layer(components);
@import url("./7-trumps/utilities.css") layer(trumps);

/* Even if imported out of order below, "trumps" always wins over "components" */

8. Introducing ITCSS into an existing project

A full rewrite to ITCSS is rarely realistic for grown projects and usually not necessary either. The most pragmatic entry point is to organize new rules according to the ITCSS scheme from the start, while existing rules are gradually migrated into the right layer whenever they need to be touched anyway. A separate folder for new ITCSS files, imported after the existing legacy stylesheet, allows both systems to coexist during the transition period.

A common first step is establishing the Settings layer, replacing scattered hex color values and magic numbers throughout the existing CSS with custom properties, without immediately changing the structure of the remaining rules. This step alone already delivers measurable benefit, because future color or spacing changes can happen centrally, even before the full ITCSS migration is complete.

9. ITCSS compared to other organizing principles

ITCSS does not compete directly with BEM or Utility First, it is more of a meta level that defines where rules are placed in which layer, independent of the naming convention used within those layers. The following table still compares ITCSS with the most common alternatives for stylesheet organization, to place their respective strengths.

Approach Organizing principle Specificity control Fit
ITCSS By specificity and reach Explicit, seven levels Large teams, long lived projects
By file type Component, layout, utilities separated None, purely organizational Small projects
7-1 pattern (Sass) By feature folders Implicit via import order Sass based projects
Atomic Design By UI complexity (atom to page) Not directly addressed Component libraries

In practice these approaches do not exclude each other. A team can use Atomic Design for component hierarchy and ITCSS for the order of the underlying CSS rules at the same time, because both answer different questions, namely how components are structured versus in what specificity order their rules are loaded.

Mironsoft

CSS architecture, design systems and frontend refactoring

Is your CSS growing uncontrolled with every release?

We restructure grown stylesheets according to ITCSS principles, introduce native Cascade Layers and make specificity in your project predictable again, without a big bang rewrite.

ITCSS migration

Gradual introduction of the seven layers into existing stylesheets

Cascade Layers

Native layer structure for robust, import order independent specificity

Architecture review

Analysis of existing specificity conflicts and a concrete refactoring plan

10. Summary

ITCSS solves the core problem of grown stylesheets by ordering rules by specificity and reach instead of by file type or chance. The seven layers, Settings, Tools, Generic, Elements, Objects, Components and Trumps, together form an inverted triangle running from broad, generic rules to narrow, highly specific exceptions. This CSS architecture makes it predictable which rule wins, without a developer needing to know the entire import history of a project.

Native Cascade Layers strengthen this benefit further, because they guarantee layer order independent of the actual file order in the build. For teams looking to newly adopt ITCSS, a gradual migration is more realistic than a full rewrite, starting with the Settings layer and a clear convention for new rules, while existing code is caught up whenever convenient.

ITCSS: Scalable CSS Architecture — The essentials at a glance

Seven layers

Settings, Tools, Generic, Elements, Objects, Components, Trumps, ordered from generic to specific.

Specificity control

Stylesheet order matches the specificity hierarchy, instead of arbitrary import history.

Cascade Layers

Native @layer declaration makes layer order robust and independent of file order.

Adoption

Gradual migration, starting with Settings, instead of a full rewrite.

11. FAQ: ITCSS and scalable CSS architecture

1What does ITCSS mean?
Inverted Triangle CSS, an architecture with seven layers from low to high specificity.
2The seven layers?
Settings, Tools, Generic, Elements, Objects, Components, Trumps.
3Compatible with BEM?
Yes, ITCSS governs the layer, not the naming convention within the Components layer.
4What belongs in Trumps?
Utility classes and rarely, documented !important declarations.
5Objects versus Components?
Objects purely structural without color, Components with full visual responsibility.
6Does ITCSS need a preprocessor?
No, works in plain CSS via custom properties and Cascade Layers.
7How do Cascade Layers help?
@layer guarantees layer order independent of actual file order.
8Gradual introduction possible?
Yes, new rules follow the scheme, existing ones migrate over time.
9Most common beginner mistake?
Too many rules in Trumps instead of the appropriate, less specific layer.
10Does ITCSS compete with Atomic Design?
No, both solve different questions and can be combined.