Thoughts on utility-first approaches in CSS

Nashe Omirro - Feb 17 - - Dev Community

With Tailwind reaching 6,000,000+ weekly downloads on NPM, as well as becoming my personal go-to for hobby projects, I wanted to understand why it got so popular... And I believe the one primary reason is an issue within CSS that bothered developers for so long:

Class naming is "hard"

Is that it? Well, yes but it goes further than that. So let's first ask why class naming is hard.

Look at these two pictures, they are both doors.

A side by side comparison of two different doors

If we were to name this doors just like how we do in CSS, Let's ignore best practices for a second and call the first door something like yellow_door and the other brown_door.

Simple right? Now what if we had a slightly different looking door that's also brown, what then?

There are two ways we've come up with to solve this, renaming the doors to be more descriptive or using some form of modifiers:

  • normal_brown_door and modern_brown_door
  • brown_door and brown_door --modern

Okay.. Then what if we add 10 other doors with various sizes, colors, the amount of inner squares they have, the design they follow, oh wow!

What a headache... Well technically we can create some sort of structure that will name all the doors, but I'm too lazy to do that.

Class naming isn't hard per se, what's hard is avoiding the consequences of poorly named classes.

"Should I use modifiers for this? Should I create a base class? Should this class "extend" from the base class even when it shouldn't use some of the base class's styles? Should I instead refactor the base class into two classes or move some of the styles of the base class to one that inherits from it? Should I just copy the styles into a new class, do I need it connected to the base class in the first place?"

Questions like these attempt to make our CSS more maintainable in the long run, and solving said questions is a pain.

The natural way we "name" things

Okay then, since these doors are real, how do we describe them in real life? Simple! We describe them the same way: yellow door, brown door. If we had more doors, we'd get more descriptive.

A person calling someone at his desk

Picture this, you are on a call with a friend that's right outside and they're looking for the house that you live in. How would you direct them to the building?

The natural way we'd do it is to describe the building no? It's a two-story house, it's egg white, it has a red roof, the door is black and modern looking, etc. The more descriptions you add, the more better they could find the place. For many people, describing the house is the first thing that comes to mind. Yes, guiding them to the house is arguably more common but guess how we guide them? we describe landmarks and things that they see visually.

Getting to the point

Now imagine describing your house in succinct one-liners, it becomes harder doesn't it? Especially if there are other identical houses near you.

That's what we're doing with class names, we are trying to put descriptions of things and compressing them into shorter names and trying to make logical structures out of them. Wouldn't it be more easier if we just use the descriptions themselves?

Developers are built different

Developers focused on programming

As web developers, we understand CSS properties like how we would understand visual descriptions in real life, and that's exactly what a utility-first approach enables us to do in code.

A way for developers to visually describe an element instead of naming and creating OOP-like naming conventions for them. No need to name things that are just too abstract.

Components are easier to logic about

That's nice and all but we still have to "name" things, we have to name our components, and we still need to group styles into it.

That's true, even with a utility-based approach we can't avoid that, but we still drastically avoid naming abstract objects and we let our components handle the structure instead (which is somehow easier). When we create components, there is some logical sense behind it, whether it's because it has some functionality attached or maybe it's an easily-named object.

Now at this point, free reign is given to the developer with how they create their component libraries/systems, but it isn't cluttered by impossible-to-name objects and they only have to worry about their components as a whole. That div that has flex and auto-margin left in the Navbar component doesn't need a name, just described, and that Button's styles could be modified and overridden with props instead of using classes.

TLDR

Correctly naming things are hard, especially one's that are abstract in nature, describing them is easier, that's what a utility-first approach lets us do.

Drawbacks

The only implementation of this approach is none other than what first introduced it, Tailwind. Now it's really nice to not worry about naming... But then you end up with a messy hot pile of utility soup, which I and many other developers would agree is not ideal.

Some accept it as a tradeoff, while others think that it's too much of a con for what it offers. I personally feel that it should do better with it's @apply directive, making it easier to hook in to tailwind's internals but it's currently frowned upon to even use it, which feels like Tailwind leaning more towards a "utility-only" approach rather than what it claims.

. . . . . . . . . . .