BEM burned us out. Utility-first CSS burned us out differently. What we need is not another naming convention or a framework that ships 20,000 classes. We need a mental model. CUBE CSS — Composition, Utility, Block, Exception — is that model. It was created by Andy Bell, and it is the most pragmatic CSS architecture I have used in production.
CUBE CSS is not a framework. It is a way of thinking.
Composition handles the macro layout. These are your grid systems, your flow utilities, your spacing primitives. They are global, they are reusable, and they never care about what lives inside them. A composition class only controls where things go, never what they look like.
/* Composition: layout only */
.cluster {
display: flex;
flex-wrap: wrap;
gap: var(--space, 1rem);
}
.switcher {
display: flex;
flex-wrap: wrap;
gap: var(--space, 1rem);
}
.switcher > * {
flex-grow: 1;
flex-basis: calc((var(--threshold, 30rem) - 100%) * 999);
}
/* The switcher becomes a column below the threshold */
/* No media queries needed — pure flexbox magic */Utilities are your design tokens in class form. Colors, fonts, spacing, borders. They are immutable. A utility class does one thing and it does it everywhere the same way. This is where you can borrow from Tailwind without importing all of Tailwind.
/* Utility: single responsibility */
.bg-surface { background-color: var(--color-surface); }
.text-primary { color: var(--color-text-primary); }
.p-md { padding: var(--space-md); }
.radius-sm { border-radius: var(--radius-sm); }
/* Usage: compose in HTML */
<article class="bg-surface text-primary p-md radius-sm">
<h2 class="text-xl font-bold">Title</h2>
<p class="text-sm text-secondary">Description</p>
</article>Blocks are your components. A card, a button, a navigation menu. They are scoped, semantic, and they own their internal structure. But unlike BEM, a block does not own its spacing or its position in the layout. That is the composition's job. This separation of concerns is what makes CUBE CSS maintainable at scale.
Exceptions handle the edge cases. A block modifier that changes one property. A data attribute that toggles a state. Exceptions are surgical, not structural. They do not redefine the block — they nudge it. When you find yourself writing more than three exception classes for a single block, that block needs to be split into smaller blocks.
The beauty of CUBE CSS is that it works with any tooling. Write it in plain CSS, in Sass, in PostCSS, or even alongside Tailwind. The methodology is the constant. The implementation is flexible. After two years of using it across three production codebases, I can say this with confidence: it is the only CSS architecture I have used that did not collapse under its own weight.
Comments