Manufacturing Sadness With CSS Classes
Tags: css, html, javascript, react
Published: 2020-03-16 23:07:11

At its best, software development is an extended exercise in _evolution_.  Our tools evolve.  Our practices our evolve.  Our frameworks evolve.  ("Standing on the shoulders of giants"... and all that.)

But evolution isn't always a straight-line march from worse-to-better.  In fact, sometimes it feels that there's a certain banality passed down from one dev to another, like a generational curse.  Or some sad rite of passage.  Like hazing, it's the idea that:

> _I_ dealt with this.  And eventually got used to it.  So _you_ should have to experience the same sadness as well.

In the world of software development, there are probably too many _sads_ for any one person to count.  So in this post, I'm going to focus on a very specific subset of _sads_: the _CSS Class Sads_.  

## The Obligatory Disclaimers

If you're the type who browses through dev-blogging sites like this one, you probably already have enough experience to realize that CSS classes are a _net good_.  I remember when CSS was _introduced_.  (Yeah... you read that right.  I'm _that_ old.)  Up to that point, it wasn't _that much_ of an exaggeration to say that we were making websites by scribbling HTML on cave walls with charcoal.  

So nothing in this article is against the overall idea of CSS.  CSS is a godsend that only improves over time.  But while CSS is easily defined as a _net_ good, like any other convention, it can be abused.  In some cases, it's abused to the point of spreading that sadness to any other devs who are unfortunate enough to dive into the code.

## The Sadness of CSS Class Dictatorship

We've all met CSS Class Dictators.  Heck, you might even _be_ a CSS Class Dictator.  (If you are, then _kudos_ to you for joyfully spreading all that yummy sadness!)  Dictators are not confined, in any way, to CSS classes, nor to CSS in general.  Every aspect of tech has its share of Dictators.

Dictators have decided (for themselves, for the whole team, for the entire company - and indeed, even for _the whole world_) that Technology X is **The One True Solution To Rule Them All** (and in the darkness, bind them).  If you don't slavishly share their universal devotion to Technology X, you're stooopid, and deserving of any scorn that comes your way.  For Dictators, Technology X is like a hammer - a hammer that's the _only_ tool in their tool belt - and the entire world appears to them like nothing but an endless series of nails.

From the beginning, CSS always had the option to apply styles _inline_ (with the `style` attribute), or through shared CSS classes (with the `class` attribute).  And from the beginning, there were people screaming to anyone who'd listen that inline styles:

- Cause premature baldness.

- Are responsible for world hunger.

- Are an attack vector for third-world covert operatives.

- Smell like feet.

This mindless devotion to CSS classes - devoid of any context in the real-life codebase - was always hard enough to manage when we were dealing with plain-ol' static vanilla HTML.  But with the current generation of rich internet applications, a slavish requirement for All-CSS-Classes, All-The-Time can be a downright hindrance to efficient programming. 

Consider the following examples that are very similar to things that I'm dealing with _even to this day_:

```javascript
// Example 1
render = () => {
   return (
      <>
         <div style={{
            float: 'left',
            borderTop: '1px solid green',
            fontSize: '1.3em',
         }}>div1</div>
         <div style={{
            float: 'right',
            borderBottom: '1px dashed orange',
            fontSize: '1.1em',
         }}>div2</div>
         <div style={{
            clear: 'both',
            borderLeft: '2px dotted red',
            fontSize: '0.9em',
         }}>div3</div>
      </>
   );
};

// Example 2
render = () => {
   return (
      <>
         <div style={{
            textAlign: 'justify',
            borderTop: '1px solid green',
            fontSize: '1.1em',
         }}>div1</div>
         <div style={{
            textAlign: 'justify',
            borderTop: '1px solid green',
            fontSize: '1.1em',
         }}>div2</div>
         <div style={{
            textAlign: 'justify',
            borderTop: '1px solid green',
            fontSize: '1.1em',
         }}>div3</div>
      </>
   );
};
```

So here's the $100,000 question:  

> Of the two examples above, should they _both_ be converted to use CSS classes?  Should _neither_ of them use CSS classes?  Should Example 1 use CSS classes and not Example 2?  Or vice-versa?

If you think that _both_ of the examples should be using CSS classes, then rest assured that your CSS Class Dictator Starter Kit is already in the mail.  It should be arriving any day now, complete with a red armband and some sturdy boots that are ideal for goose-stepping.  

It doesn't take a rocket scientist to see that Example 1 consists of three _entirely unique styles_ applied separately to each of the `<div>`s.  Furthermore, without seeing any context for the rest of the app, there's no particular reason to believe that these sets of style attributes would ever be used anywhere else.  

Conversely, Example 2 has the _exact same set of style attributes_ applied to all three `<div>`s.  If you've ever heard of **DRY** (go ahead... Google it... I'll wait) then it's not hard to see why that repeated set of styles should be encapsulated in its own CSS class. 

(**Note:**  Yes - I realize that, in JavaScript/React, we _still_ don't have to put the repeated style sets into _classes_.  We could, in theory, just encapsulate them in a shared _object_ and pass that object into the `style` for all elements that require that particular styling.  But I'm not even going to dive into _that_ debate within the scope of this article...)

You see... CSS classes are basically just a means of sharing style.  In fact, in CSS, that's pretty much _all_ that a "class" is - because CSS "classes" have absolutely nothing to do with OOP "classes".  CSS "classes" don't even have anything to do with _JavaScript_ "classes".  In CSS, a "class" is pretty much just a _shared bucket_.  

> If you're not limiting your CSS classes to styles that are _shared_ between two-or-more elements/components, then your classes are pretty much a waste of time - an unnecessary and potentially _harmful_ abstraction.

(**Note:**  Yes - I realize that CSS classes can have _some_ benefits with regard to pre-compiling in the browser.  In 99%+ of those cases, the "benefits" of said pre-compiling amount to micro-optimizations.  If your app is bogging down because of all those unprocessed styles... you have bigger fish to fry than class-vs-inline-style debates.)

I don't know why this is so hard.  But apparently... it is.  Because I've run into so many places (even _recently_) where some CSS Class Dictator in the team/company has _dictated_ that, "There will be NO inline styles!!!"  And they somehow think that they've enforced good coding standards - when all they've done is spread _the sadness_.

It doesn't matter to Dictators if the CSS files are clogged with huge volumes of single-use classes that are incredibly specific to an exact element, being rendered in an exact component, in an exact module.  In fact, _nothing_ matters to them - other than the slavish devotion to the no-inline-styles rule.

## The Sadness of Style Attributes Masked by CSS Classes

Dogmatically insisting that there can be **no** inline styles can lead to some weird side effects.  These side effects aren't just a syntax choice - like arrow functions vs. old-skool function declarations.  _They actually undermine the original intent of the `class` and `style` HTML attributes._

Consider this simple example, written originally with inline styles:

```javascript
render = () => {
   return (
      <SomeComponent style={{textAlign: 'right'}}>
         Lorem ipsum - blah, blah, blah...
      </SomeComponent>
   );
};
```

Doesn't get much more basic than this.  We have a block of text and we want that text to be right-aligned.  So we just slap the easiest, and most targeted, solution on it that's possible:  We use `style` to set the component's contents to right-aligned.  As simple as that might sound, it gets kinda strange when you're working with CSS Class Dictators.  

Right now, I'm contracting for a public entity that uses their own "design system".  There's nothing wrong with the idea of a "design system".  In fact, they can be quite useful.  But the system _dictates_ that the code above should be done as follows:

```javascript
render = () => {
   return (
      <SomeComponent classNames={'ds-u-text-align--right'}>
         Lorem ipsum - blah, blah, blah...
      </SomeComponent>
   );
};
```

At first glance, you might think:

> Class/style.  Poe-tay-toh/poe-tah-toh.  What difference does it make??

OK, fine.  Then tell me what you think of _these_ examples:

```javascript
// Example 1
addTwoNumbers = (number1 = 0, number2 = 0) => number1 + number2;
const sum = addTwoNumbers(2, 2);

// Example 2
const sum = 2 + 2;
```

If you think that Example 1 is just fine, then you can stop reading right now.  And please, no matter what you do for the rest of your life, never show yourself on any dev team of which I'm a member.

Example 1 purports to re-create, with unnecessary verbiage, something that _already exists in a cleaner, more-efficient manner_ in core JavaScript.  So with that in mind, Example 1 is empirically _bad_.  

(**Note:** Unilaterally labeling almost _anything_ in tech as a universal "good" or a universal "bad" is, admittedly, a very risky position to take.  Most things in tech are "good"... in _certain_ situations.  And "bad"... in _other_ situations.  Nevertheless, I'm perfectly comfortable stating that Example 1 above is absolutely, positively _bad_.)

What does any of this have to do with CSS classes?  Well, if you've created a CSS class called `ds-u-text-align--right`, and its sole purpose is to right-align its container's text, well... that's _bad_ as well.  That CSS class is nothing more than an attempt to re-create, with unnecessary verbiage, something that _already exists in a cleaner, more-efficient manner_ in core CSS.  So with that in mind, the `ds-u-text-align--right` class is empirically _bad_.

Re-creating style attributes as CSS classes is also harmful because the team that creates the "design system" rarely ever takes the time to convert _all_ of the CSS style attributes into standalone classes.  They only convert the CSS style attributes _that they find themselves frequently using_.  This means that, as a _user_ of that same design system, you have little choice but to mix-and-match items defined in the system with your own custom classes - or your own inline styles.

For example, while complying with this current design system, I'm forced to write code that looks like this:

```javascript
render = () => {
   return (
      <>
         <SomeComponent classNames={'ds-u-overflow--scroll'}>
            Some content...
         </SomeComponent>
         <AnotherComponent style={{overflowX: 'scroll'}}>
            More content...
         </AnotherComponent>
      </>
   );
};
```

Notice that, in the first component, I'm using a CSS class for `overflow`, as prescribed in the design system that I've been asked to comply with.  But in the second component, I'm using an inline style attribute for `overflowX`.

Why have I used these mismatched approaches right next to each other?  Is it because I don't care about consistency in my own code??  Hardly.  It's because the design system couldn't be bothered to define a standalone wrapper class specifically for `overflowX`.  It only defines a wrapper class for `overflow`.  So if you want to invoke the `scroll` value - but you _only_ want to invoke it on the X-axis??  Well... then you're on your own.

I _could_ submit a pull request to the design system's GitHub.  But if you think I can be bothered to do that - and to wait for the desired merge to occur - then you have no idea about the deadlines I'm typically working on.

I _could_ create my own custom CSS class called `ds-u-overflowX--scroll`.  And that would _look_ consistent to any dev who's casually reading through the code.  But it would be horribly INconsistent under the hood.  Because a logical assumption would be that anything starting with that `ds-u-...` prefix would ultimately derive from the design system.  But that logical assumption gets shredded if I start creating _my own_ `ds-u-...` CSS classes that live in the local source directories of my app.

## The Sadness of CSS Class Names

Global, _dictatorial_ use of CSS classes (in lieu of _any_ inline styles) also causes naming problems.  Because style elements can be assigned to nearly _any_ element, and used in nearly _any_ context, it can be difficult to give them meaningful names that also avoid naming conflicts.  

The CSS Class Dictators have an answer for this.  It's an answer that spawns its own set of headaches, but it's _technically_ an... answer.  They came up with (obtuse) naming conventions to avoid collisions.  

There's no Single Rule For CSS Class Naming, but a common one you'll see all over is the BEM syntax.  There's nothing particularly intuitive about that acronym, so I'll just tell you what it stands for: Block Element Modifier.  

The fact that "BEM" doesn't naturally lead anyone to infer "Block Element Modifier" is no accident.  That opaqueness is consistent with most apps that actually use BEM - and I've seen it in a great many apps.  There are many other naming conventions that you could use for your CSS classes, but BEM seems to be particularly common.

The BEM naming rules call for CSS class names to be formatted like this:

`[NAMESPACE]-[PREFIX]-[BLOCK]__[ELEMENT]--[MODIFIER]`

Oh, mannnn... That's a lotta info to try to cram into a single identifier.  In fact, it's so much information that it could easily lead to ridiculously-long class names.  

Consider the following hypothetical eyesore:

```javascript
render = () => {
   return (
      <ChildComponent classNames={'ourcompany-thiscomponent-childcomponent__overflow--scroll'}>
         Some content...
      </ChildComponent>
   );
};
```

All of that junk piled into the class name - when you simply could have done this:

```javascript
render = () => {
   return (
      <ChildComponent style={{overflow: 'scroll'}}>
         Some content...
      </ChildComponent>
   );
};
```

Of course, I'm not the first person to point out that a given variable or naming convention might be unwieldy.  CSS acolytes recognize these problems as well.  So do they fix it with greater use of inline styles??  Of course not.  That would be stooopid.  No - they fix it with minuscule abbreviations that are far shorter - but much harder to read and understand.

Consider the example class that I showed you above from my real-life project:

`ds-u-overflow--scroll`

> Hmm... What does that mean??

Well, I'll assume that most of us can figure out what `overflow--scroll` maps to.  But what about `ds-u`?

- The `[NAMESPACE]` of `ds` refers to "design system".
- The `[PREFIX]` of `u`refers to "utility".

Could _any_ outsider surmise those values merely by reading the code??  _Of course not._  There's absolutely nothing intuitive about "ds" or "u".  They're so short and so vague that they could mean almost anything.  

If a junior dev on my team submitted code that looked like this:

```javascript
const ds = 'someValue';
const u = 'anotherValue';
```

I'd **deny** the pull request - and tell him to fix it.  It's just not fair to expect other devs, encountering those variables for the first time, to have any idea what "ds" or "u" convey.  But we tolerate this in BEM class names, because no one wants to see long names stuffed into every dang "class" attribute in their app.

If the users of the design system had to put `designsystem-utility-` in front of a huge number of their CSS classes, they'd get annoyed.  So to get around this (entirely unnecessary) problem, they create an entirely different problem by making their code obtuse and difficult to read.

## The Right Tool For The Job

I often use the analogy of _tools_.  As a programmer, I have _soooo_ many quality tools at my disposal. Some of those tools get used every single day.  Some of them get used only once every few months (or less).  But nearly every tool has a purpose.

Walk into an artisan's shop and look at the array of tools on the bench or on the wall.  Some of them are rarely used.  Some of them are sturdier than others.  They can be cheap or expensive.  But artisans don't point to one tool and call it "good" or "right", and then point to another tool and call it "bad" or "wrong".  They understand that for every job, you want _the right tool for that job_.

Unfortunately, many programmers don't (or refuse to) grasp this concept.  They get all fired up about CSS classes.  Then they decide that CSS classes are The Only True & Acceptable Solution.  If they get enough clout in their team/company, they even create arbitrary rules like: "NO inline styles!"  Then they nearly slip a disc as they jump through all sorts of painful obstacles to solve the follow-on problems that result from their rigid (and arbitrary) dictates.

## Understand Your Tools

It's sad that I have to write this, but the proliferation of crappy CSS classes convinces me that _someone_ needs to hear it:

- CSS classes are for repeated/re-used _collections_ of style attributes.  If you're never going to use this particular collection anywhere else in the app, then you're creating unnecessary complexity (and obscurity) by shipping those attributes off into CSS classes.  If you're creating CSS classes that consist of _a single style attribute_, then you are **_the definition_** of "reinventing the wheel".<br/><br/>

- Inline styles are for adding single style attributes to an element.  Or for adding an ad hoc _collection_ of style attributes that are _unique to this element_.  If this collection of attributes is _not_ unique to this element, then bundle them up into a CSS class - and re-use that single class wherever necessary.<br/><br/>

There... _Was that really so hard???_