Code-efficient Theming and  Coloring in CSS thanks to an OOP-inspired pattern
Tags: css, html, webdev, scss
Published: 2020-11-12 14:07:58

**I'd like to introduce a pattern for writing CSS** I've been using in production for almost a year now **that aims at solving the hassle of theming and coloring in CSS.** 

This pattern helped me reduce by 60-90% the size of my CSS code related to coloring and theming compared to libraries like Bootstrap or Semantic.

Warning : If you're a beginner, you might find this too abstract, so I advise you to read what follows only if you have already a bit of experience doing front-end design. 

## Introduction : context and pattern requirements

To introduce a bit what comes next, here are a few words about my view on front-end design. I've been web-designing since 1999 (starting with the infamous Microsoft Front-Page). I have written quantities of front-end code, for platforms and frameworks like Dotclear, Wordpress, Drupal, making full-fledged Django applications, React, while I still enjoy writing static sites and pure HTML+CSS. I am confortable saying I am quite familiar with not only the DOM syntax, but also with the _DOM rationale and philosphy_, which is my opinion amounts to kepping the three languages (HTML / CSS / JS) separated by function. As for CSS (the topic of the day), CSS should be as much as possible the only language to take care of styling. HTML shouldnt take care of CSS (avoid using `style` property), JS shouldnt take care of CSS (avoid using CSS-in-JS, CSS modules, or setting properties in JS). Nevertheless these languages can be _interfaced_, namely (in a simplified way) HTML interfaces with CSS using _classes_ and _ids_, and JS can interface with CSS setting _classes_ and _ids_ dynamically. Of course, there may be some exceptions to doing front-end this way, but it's a philosophy I like to stick to as much as I can, it makes my code clean, predicable and maintainable.

Let's get back to our problem. **I wanted to expose a theming and coloring CSS library that fullfiled the following requirements :**

+ **Having a large color palette** that encompasses the color wheel (red, blue, pink ... green), monochrome shades (grey, black, white ...), social network shades (instagram, twitter, google), modal shades (success, error, warning)
+ **Storing the colors in variables, whether using preprocessor variables (SCSS)** or [native CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) (aka "CSS custom properties", also sometimes wrongly called "CSS4 variables"). So these can be customized by compiling a custom version of the library.
+ **The CSS color API doesn't need to know anything at all about all the other parts of my front-end.** In other words, the CSS must completely be framework-agnostic (so to avoid being locked down in a way of doing things, like styled components or bootstrap.) 
+ Also, **the CSS color API must be provided separately from any components or html code**. Again, this means the color API cannot know anything about the rest of the front-end framework. 
+ **Doing all of this in a way that respects the DOM philosphy** (C in CSS means cascading, so no CSS modules or weird [CSS-in-JS naive reinterpretations of what CSS should be](https://gomakethings.com/whats-wrong-with-css-in-js/)). I just want to import a CSS file into my HTML and leverage the color API out of the box. But I also want to be able to include it in more complex React applications, for instance, and leverage it when designing components.
+ Last but not least : I would consider being successful in designing such a CSS library if **I manage to reduce the quantity of code necessary** to color components using it **from polynomial** to **linear**. Yes, because traditional component libraries such as Bootstrap, Semantic, Material-UI, even Tailwind CSS, encourage you to write "one class per color per component". Instead, **I'd like to have only "one class per component", meaning CSS component classes must be able to understand any color.**
+ **Bonus : Making this color API expose custom themes, like a dark theme.**

## What we want to avoid : writing a polynomial number of classes to style components per color

Let's look at how Bootstrap works. This is very illustrative of the mainstream way of doing component coloring and theming, and libraries like Semantic-UI and Tailwind offer a similar syntax for classes.

If we look the styling of a button in the bootstrap source we have 
```
@each $color, $value in $theme-colors {
  .btn-#{$color} {
    @include button-variant($value);
  }
}
```
[`(bootstrap/scss/_buttons.scss)`](https://github.com/twbs/bootstrap/blob/main/scss/_buttons.scss)

Here, in theory the SCSS is quite neat. The code is readable and understandable. You can see that we loop through a hash of colors and define **one class per color**. The problem is with the compiled output.

This way of writing classes is actually **very unefficient**. 

Why ?

Because this makes us compile to a polynomial quantity of code :
+ If we have a number `i` of colors (red, green, blue, yellow ...)
+ and a number `n` of components (button, card, modal, ...)
We would end up having **`i * n` CSS classes**. (`Number of colors` times `number of components`). If we increase one or the other, this has a polynomial (> linear) effect on the size of the compiled output. This will make your CSS files huge, with all the issues that come with it (increased page loading time, browser unable to pick up what's really important to render, not to mention hard to read compiled output for debugging).

## A code-efficient pattern for coloring, inspired by OOP, using CSS variables

Let's take a look at what [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) can do for us. For the sake of example simplicity, we'll say we have 3 colors : red, blue and yellow.

### First, let's store the colors in CSS variables

We store the variables according to the spec the colors in the root HTML element. Namely :

```
:root {
  --red:#DF2F00;
  --yellow:#FFDA22;
  --blue:#89A6FB;
}
```
`(main.css/main.scss)`

If we're using a preprocessor, we could have something like this to make it a bit more maintainable

```
$colors:(
  "red":#DF2F00;
  "yellow":#FFDA22;
  "blue":#89A6FB;
)!default;

@mixin define-root-variables {
  :root{
   @each $color, $value in $colors{
     --#{$color}:#{$value};
   }
  }
}
```
Then, if we don't look to improve on having the polynomial number of classes, we would write component classes like this 

(I'm just adapting the bootstrap code, don't do this at home kids!)
```
@each $color, $value in $theme-colors {
  .btn-#{$color} {
    @include button-variant(var(--#{$color})); //We don't need to provide the value anymore because the CSS var takes care of it !
  }
}
```

At the moment, this doesn't seem like a huge improvement and it is not ! ... but wait, the magic has yet to come. We're almost there.

### Introducing Setters and Getter classes

Taking inspiration from the world of Object-Oriented Programming, we create helper classes which we call _setters_ and _getters_, that set and read a local variable. 

Setters set `:root` variables to an intermediate variable that we call (at the moment, in a bit verbose way) `--current-color`. 

Getters consume the locally set `--current-color` to apply it to an element in a particular way.

An example is worth a thousand words :

{% codepen https://codepen.io/dr-no/pen/VwjqMjb default-tab=css,result %}

**As you can see, with this approach :**
+ We only have to create one class per 'use-case', in the example we provided three (text color, background color, and a transparent button). This class is compatible with all the colors.
+ Subsequently, the theming of html block or components only requires, for `n` components and `i` colors : 
  + `i` classes for the color setters
  + `n` classes for the components
  + = **`n+i` classes** which is linear.

**Let's take a second to realize the code savings:**
+ **For 5 colors (`i=5`) and 10 components (`n=10`)**, the "classic" approach would imply the creation of `i*n = 5 * 10 = 50` CSS classes, whereas the Setter/Getter pattern would only create `i + n = 5 + 10 = 15`. This is a **70% reduction** in the number of CSS classes needed.
+ **For 10 colors (`i=10`) and 20 components (`n=20`)**, the "classic" approach would imply the creation of `i*n = 10 * 20 = 200` CSS classes, whereas the Setter/Getter pattern would only create `i + n = 10 + 20 = 30`. This is a **85% reduction** in the number of CSS classes needed.
+ **For 15 colors (`i=15`) and 100 components (`n=100`)**, the "classic" approach would imply the creation of `i*n = 15 * 100 = 1500` CSS classes, whereas the Setter/Getter pattern would only create `i + n = 15 + 100 = 115`. This is a **93% reduction** in the number of CSS classes needed.

A few limitations of this approach (at this point, as we will solve most of them in the part 2) :
+ The CSS classes used above as _setters_ are quite verbose (`.current-color-red`), this can be improved before using this in production
+ If we wish to have more complex color interactions, such as changing color shade/tint on hover, or contrasting the text automatically, we need a slightly more complex pattern, but it's completely feasible in a linear number of classes as well. Look at the second part of the article for how to do this.
+ The CSS vars are only compatible with 95%+ of browsers. This will not make it in IE11.

## Conclusion

By using an intermediate class we call _setter_, that acts in between the component class (_getter_) and the `:root` CSS variables, we are able to reduce the quantity of CSS classes needed to style components from a polynomial number to a linear number.

I write this hoping to give you some inspiration on how to improve your theming and coloring game. IMHO this is long overdue in 2020 ! 

If this helped you, I invite you to look at Swatch ([docs](https://swatch.dev) | [github](https://github.com/fwrlines/swatch) ), a library that exposes this pattern in CSS with more than 80 colors. And it's only 2.5KB gzipped. If you like it, a star on github would warm our heart !

## In the part 2 of the article (coming soon)

+ I will introduce the CSS library Swatch ([docs](https://swatch.dev) | [github](https://github.com/fwrlines/swatch) ), that exposes a coloring API based on the previous pattern. We will take a look at how to use it in just a few minutes :)
+ We will see how to use this pattern with Swatches of colors (dark, normal, light, contrast), to make coloring more complex, interesting and interactive

Thank you for reading !