
Composition in CSS
Composition in CSS êŽë š
Tailwind and other utility libraries have been huge proponents of composition. But, to me, their version of composition has always carried a heavy sense of naïveté.
I mean, utility composition is basically adding CSS values to the element, one at a timeâŠ
<div class="p-4 border-2 border-blue-500"> ... </div>
If weâre honest for a minute, how is this composition different from adding CSS rules directly into a class?
/* This is composition too! */
.card {
  padding: 1rem; 
  border: 2px solid var(âcolor-blue-500)
}
That said, I canât deny the fact that Iâve been thinking a lot more about composition ever since I began using Tailwind. So, here are a couple of notes that Iâve gathered together about CSS composition.
Itâs not a new concept
CSS is a composable language by nature. This composition nature is already built into the cascade. Letâs say youâve decided to style a button with a few properties:
.button {
  display: inline-flex;
  padding: 0.75em 1.5em; 
  /* other styles... */
}
You can always tag on other classes to modify the buttonâs appearance:
<button class="button primary"> ... </button>
<button class="button secondary"> ... </button>
.primary { background: orange; }
.secondary { background: pink; }
You can even change the appearance of other elements to a button by adding the .button class:
<a href="#" class="button"> ... </a>
Composition is happening in both cases:
- We composed 
.buttonontoa - We composed 
.redonto.button 
So, CSS composition has been in existence since forever. We simply donât talk about composition as a Big Thing because itâs the nature of the language.
Developers take a pretty narrow view of composition
When developers talk about composition in CSS, they always seem to always restrict the definition of composition to the addition of classes in the HTML.
<div class="one two"> ... </div>
Whatâs interesting is that few people, if any, speak about composition within CSS files â from the angle of using Sass mixins or advanced Tailwind utilities.
In these cases, we are also composing styles⊠just not directly in the HTML!
@mixin button () {
  display: inline-flex;
  padding: 0.75em 1.5em; 
  /* other styles ... */
}
.button {
  @include button; 
}
What is composition?
Composition comes from two possible words:
- Compose: Put together
 - Composite: Made up of distinct parts or elements
 
Both words come from the same Latin root componere, which means to arrange or direct.
In other words⊠all work is put together in some way, so all work is composed. This makes me wonder why composition is used in such a limited context. đ€
Moving onâŠ
Composition doesnât reduce bloat
Class composition reduces CSS bloat only if youâre using utility classes. However, class composition with utility classes is likely to create HTML bloat.
<div class="utility composition">...</div>
<div class="one utility at a time">...</div>
<div class="may create html bloat">...</div>
On the other hand, class composition with selectors might not reduce CSS bloat. But they definitely introduce lesser HTML bloat.
<div class="class composition">...</div>
<div class="card primary">...</div>
<div class="may override properties">...</div>
<div class="less html bloat"> ... </div>
Which is better?
HTML bloat and CSS bloat are probably the least of your concerns
We know this:
- HTML can contain a huge amount of things and it doesnât affect performance much.
 - CSS, too.
 - 500 lines of CSS is approx 12kb to 15kb (according to Claude).
 - An image typically weighs 150kb or perhaps even more.
 
For most projects, optimizing your use of images is going to net you better weight reduction than agonizing over utility vs. selector composition.
Refactoring your codebase to decrease CSS bloat is not likely to increase performance much. Maybe a 2ms decrease in load times?
But refactoring your codebase to improve developer recognition and make it easier to style? Much more worth it.
So, Iâd say:
- HTML and CSS bloat are pretty inconsequential.
 - Itâs worthwhile to focus on architecture, structure, and clarity instead.
 
Advanced compositions
If we zoom out, we can see that all styles we write fall into four categories:
- Layouts: Affects how we place things on the page
 - Typography: Everything font related
 - Theming: Everything color related
 - Effects: Nice good to have stuff like gradients, shadows, etc.
 
Styles from each of these four categories donât intersect with each other. For example:
font-weightbelongs exclusively to the Typography categorycolourbelongs exclusively to the Theming category
It makes sense to create composable classes per category â when thatâs done, you can mix-and-match these classes together to create the final output. Very much like Lego, for the lack of a better example. (Alright, maybe Duplo for the kids?)
So your HTML might end up looking like this, assuming you do class composition for these four categories:
<!-- These are all pseudo classes. Use your imagination for now! -->
<div class="layout-1 layout-2 effects-1">
  <h2 class="typography-1 theming-1"> ... </div>
  <div class="typography-2"> ... </div>
</div>
A real example of this would be the following, if we used classes from Splendid Styles and Splendid Layouts:
<div class="card vertical elevation-3">
  <h2 class="inter-title"> ... </h2>
  <div class="prose"> ... </div>
</div>
Iâm writing more about this four-category system and how Iâm creating composable classes in my latest work: Unorthodox Tailwind. Give it a check if youâre interested!
Wrapping up
To sum up:
- CSS is composable by nature.
 - Developers seem to be quite narrow-minded about what composition means in CSS.
 - You can do composition in the HTML or in the CSS.
 - Styles we write can be divided into four categories â layouts, typography, theming, and effects.
 
And finally: Splendid Styles contains classes that can aid composition in each of these four categories. Splendid Layouts handles the layout portion. And Iâm writing more about how I create composable classes in my course Unorthodox Tailwind.