ITCSS - Inverted Triangle CSS

Inverted Triangle CSS is a technique for developing easily maintainable CSS introduced by Harry Roberts.


CSS is easy to write but can easily become hard to maintain as our app scales. ITCSS solves this maintainibility issue with an approach of taking care of the specificity graph of the CSS codebase.

Specificity Graph

The structure

ITCSS introduces layers with increasing specificity. This structure should be flat, meaning no imports should be present outside app.scss.

Difference between components and objects

Originally the objects layer was created for Object-Oriented CSS (hence the name), and could be ignored. However the idea of differentiating between layout-driven and visual-driven elements is benefitial enough in terms of categorizing and thinking about the purpose of each element to keep it.

Some inheritance relationship may be in play (eg.: c-designeditor is a o-panel, c-helpbox is a o-modal), but not exclusively.


Converting checklist

Whenever implementing new CSS or converting existing CSS into ITCSS these steps may serve as guidence:

  1. Can it be a modifier? Check for own solution and add as a modifier if possible
  2. If we are using a framework –> Is it implemented in our framework? Check for module and convert it into ITCSS if possible
  3. New component –> new file
  4. Choose the right layer(s)
  5. Use ITCSS prefixing and BEM.

1. Adding as a modifier

Adding an element as a modifier of an existing one is suitable when the element can be implemented with the base block element + some of its modifiers without changing the majority of the base elements’ rules (To read about block elements and modifiers: BEM). This compels code recycling.

2. Converting our framework to ITCSS

ITCSS is designed to be structure without frameworks. Many frameworks (the most popular ones at least) weights a lot (~166kb), and most of its components are often not even being used, and those which are, are often gets overwritten by our custom rules. These frameworks once we have them, should serve as helpers in implementation, but in this setup we cannot rely on them because of their complexity and incompatibility.

Recommended way of conversion:

  1. Import the framework module by module, ignore them in production
  2. In development, locate elements you wish to implement
  3. Implement the solution by inserting the partials to the corresponding layers
  4. Comment out the framework module again
  5. Test

3. One block element, one file

Always apply BEM methodology (block-name, block-name__element, block-name--modifier). One file should always contain only one block, its elements and modifiers, and should follow the following pattern:

/*  Block */
c-component-name {
	/* ... */

/*  Modifiers */
c-component-name--modifier1 { /* ... */ }
c-component-name--modifier2 { /* ... */ }

/*  Elements */
c-component-name__element1 { /* ... */ }
c-component-name__element1--modifier1 { /* ... */ }
c-component-name__element2 { /* ... */ }
c-component-name__element1--modifier2 { /* ... */ }

/*  Original - block */
.component { @extend c-component-name }

/*  Original modifiers */
.component.modified { @extend c-component-name--modifier1 }

/*  Original elements */
component > ul > li { @extend c-component-name__element1 }
component > ul.modified > li { @extend c-component-name__element1--modifier1 }

In this pattern the original modules are only relevant if you are migrating from an already implemented framework.

Try to keep files small, and not to exceed LN 200.

4. Using the right layers

5. ITCSS prefixing

ITCSS prefixing means prefixing our classnames with either c- or o- depending wheter the element is a component or an object. This has 2 purposes:

The transition from original class name to the new one can be easily achieved without touching the markup and javascript with extends:

.o-panel {
    display: block;
    position: absolute;
    z-index: 100;
    overflow-y: auto;
    display: none;

.o-panel--active {

/* Foundation references (as is in HTML and JS) */
.panel { @extend .o-panel; } { @extend .o-panel--active; }

Note that this refactoring besides changing the class names reorganizes the structure to fit BEM. This is however a temporary solution for testing purposes, as the ultimate goal is to make the change everywhere.


NPM packages and commands analyze-css (GitHub), specificity-graph (GitHub) can be and should be used to inspect the CSS codebase in an extensive overview.

Gábor Pintér Web developer, hobby blogger, decent guy