Hey, your API surface is causing unnecessary complexity

- Posted in css rant tailwind webdev - 2 comments

I’ve been “fighting” against Tailwind for a while, and there’s 4 different kinds of reactions:

  1. Please stfu, Tailwind is awesome, [insert technical argument]
  2. Johan, why do you bore me with these technical things? Can you please tweet about cooking? And where is your new post about sim racing?
  3. If you don’t like it, just don’t use it
  4. Nod – you are right (this is mostly coming from the people from my same “generation” who learned web development around the same time as I did)

The fighting takes the form of blog posts and tweets. On the Routify Discord channel it’s already a running joke that I’m going to vent when somebody comes in to ask a Tailwind question.

Yesterday someone reached our privately, basically to challenge me to channel this negative energy into something positive. I agree that would be nice.

For now you will have to do with this blog post which is still in the rant-o-sphere. But I will take up the challenge to maybe work on something that shows my opinion on how to do it “right”. That’s going to take some time though.

Why do I get so worked up about Tailwind? Because bad frameworks create problems that shouldn’t exist.

I help to maintain Routify, at least from a community and docs perspective. Quite a few support questions that come in are about dev pipelines, and some of them about Tailwind. A CSS framework I don’t like creates a support problem for me. I cannot simply ignore it (so that’s a rebuttal against the point to simply ignore the existence of Tailwind).

What I see is that bad frameworks create a crazy learning path for new devs, where they might waste months learning to work with frameworks with crazy APIs only to find out that they haven’t really learned anything.

Learning modern web development is already intense. But at this point in time, a lot of modern web development leads you down a path where you might not learn all that much, because you are fighting poor decisions made by other people. Maybe if you’re new to this, you think that’s just the way things have to be.

One thing that I want to mention is that not everything about Tailwind is bad. I think the visual look is quite solid. The way the framework is promoted is well done, with well-produced video content and blogging that has gone professional. I mean, this team knows their stuff. I just fundamentally disagree with the premise of littering your HTML with classes. I disagree with shipping a framework that has accessibility issues.

I am often in a position where I am mentoring new hires to our company. A few months ago I pointed someone new to Adam Wathan’s article “CSS Utility Classes and “Separation of Concerns””. This is a great article by the author of Tailwind.

I guess with the above I just want to point out that I am not blind to the Good Parts of Tailwind (just like there are good parts to React ;) *shields from incoming flames*)

But overall I am worried that some framework makers live in their own theoretical world and forget about the real world. They are striving for a technically perfect framework but forego the real-life usage. For them the framework is the project and the lens they view things through. The usage and the actual project where their framework is used is just a detail. When it should be the other way around.

This kind of perspective leads to frameworks that constantly change their mind about what they want to be, leading to work down the line for the users, that often has no real-life value at all.

In my blog posts taking down Tailwind I am mainly writing from a worry of having to maintain a codebase full of classes.

Somebody tweeted this screenshot and I’m like: seriously?

Screen capture showing a VS Code window. Tailwind CSS classes which apply colors have color blocks next to them. There is a panel on the left of the screen which displays your Tailwind config in a tree view.

If you look really well you can see that this shows a heading and 2 buttons, but it’s a bit hard to see. If you’re interested why this is just a poor way to develop your things you can go back to the blog posts and see what I had to say.

Today this post is more about a broader perspective. I eventually gave this post the title “Hey, your API surface is causing unnecessary complexity”. This was triggered by Tailwind basically repackaging CSS gradients in their own proprietary syntax and then limiting what you can do with gradient because they don’t support everything. And I’m like: why not simply use CSS? Like, which problem does this solve?

It just adds to the complexity of Tailwind. It creates something new for a dev to understand when they find this code. It creates a new documentation page that has to be maintained. It creates a new surface area for bugs. I think sometimes you just have to stop developing a framework. Sometimes, things are finished. The problem with Tailwind is that since it basically mirrors CSS, it will simply never be finished as long as CSS keeps adding new features. Which they should also put a stop to, in my opinion.

I see what I’m talking about – adding unncessary complexity — happening with both SCSS and the CSS working group. In October last year, SCSS modules were announced and literally nobody cared. I love SCSS – I have been working with Sass since the early days and contributed to the first documentation site of Compass. That was my first introduction to open source. But Sass/SCSS has now reached a maturity point that what people are adding is so niche that nobody really cares anymore. Look: SCSS was already done.

Now the CSS working group is discussing some sort of cascade layering system within CSS itself.

I applaud the efforts to try and solve problems with CSS, but I also fear that maybe they are in vain. I think CSS is already complex enough. You can read my thoughts in the comment below the linked spec.


In a discussion with a fellow dev about Svelte 3, he said Svelte 3’s API is nearly perfect. There is not much to add. In a lot of the pull requests about Svelte where people try to add features, there is pushback because it will make the framework more complex. Personally I love this. I want people to be able to attain Svelte mastery. To understand the API in full.

I don’t want a framework that has a thousand nooks and crannies and that has 2 or 3 ways to do things.

In React world there is the pre-hooks way and the post-hooks way. In Ember world there is non-Octane and Octane. Vue is moving to Vue 3, but at least that is backwards-compatible.

Maybe Svelte will go to a transition at some point where there is a Svelte (4?) API that is vastly different; maybe it won’t.

But I think people should realize they can’t keep adding complexity on top of complexity. People should really stop and think if you really need 500+ Mb worth of node_modules to build a simple website. Developers need to think about the API surface of the tools they are building. There is an optimum point where it’s better to stop instead of cramming in feature after feature.

We are moving towards a world where people are doing web development where they are purging a 1.4Mb CSS file to 28kb ( for the actual selectors they used) on a CI environment that they don’t control. And then one day AWS goes down, and maybe npm gets hacked, and the poor web dev who hasn’t built up fundamental skills doesn’t really know how to do anything anymore, because they always depended on others (what is SSH anyway?).

I think people need to know fundamentals. You can’t depend on a few magical incantations on the terminal that you don’t fully understand.

The same goes for any kind of development. When you write a CSS rule you have to understand what it does and where it is coming from.

When you deploy a website you have to understand what is happening behind the scenes.

When you use a framework, you have to work towards understanding it in full. You have to know why it exists and why you use it.

If somebody wants to use Tailwind and has a set of reasons, that’s fine for me. What I don’t like is people defaulting to things that are popular and then learning a stack that basically abstracts the fundamentals; this leads to a situation where junior web devs work for 3 years but lack fundamental skills because they were too busy trying to fix local problems created by poor frameworks. And that’s what I’m fighting.

2 Comments

  • Mehdi says:

    Nodding with the whole article.

    I once had a discussion about the layout grid of a project at BigBelgianCorpo. We proposed a design, we developed the project, but then a “senior designer” came in and asked to switch the layout grid to 960px grid of 12 columns because of Bootstrap, because otherwise “things can’t fit, especially on mobile”. Everything was already fitting and developed by me – front-end developer with 2 years of experience back then –, but this person was probably told during years by developers colleagues that a grid had to be that exact size and that exact number of columns because the developers did not learned CSS.

    A couple of years later, their stack is the same (they switched to Foundation, which is the same paradigm as Bootstrap or Tailwind).

    Otherwise, you’re right about what Tailwind does well, and like Vue it gained traction thanks to Laravel (tweet). (Laravel is incredibly awesome, and I also like Vue.)

    Now, some (almost off-topic) rant: when the new SASS spec was announced (with modules, as you mention), my first opinion was that it should first modernize SASS in order to embrace CSS stuff that came into browsers during the last ten years, like being able to simply use CSS `hsl()` in SCSS (you can’t, so I created a package for this 🙃: hsl.scss).

    The new SASS spec does fix these kind of things, but in a way that will require developers to unlearn/adapt a lot how to use SASS, which was already awesome putting aside the lack of modernity. The paradigm shift is not a small one for this new spec. Main reason: the SASS cascade will lose `@import`, which will break the SASS cascade, which I think is completely wrong when it comes to a tool helping you to deal with CSS. I think it’ll damage SASS future and I write a long rant about it.

    So basically, nex3 (who’s almost the only person taking decisions about SASS) turned the CSS paradigm (cascade) into a JS paradigm (import stuff where you want to use them), and I’m absolutely not happy with that spec because it replaces a core SASS feature (cascade) in favour of a less core feature. And I find it very sad that nobody ever heard about this proposal before October 2019 because it has been in discussion since 2014 (#1094), but with virtually no communication to get feedbacks from the community. Now, it’s too late to question it because “the time for public debate of the proposal has ended.”. Yes, “public debate”.

    That’s why nobody cared: nobody saw it among the shittons of front-end news we have every day. Nobody can keep up with all the things, so 1 article on CSS-Tricks isn’t enough. For big stuff like SASS, you have to repeat and repeat until you get attention.

    As for me, I will either stick to the intermediate SASS state (with both @import and @use), or ultimately switch my whole workflow to PostCSS. But maybe it’ll make JS developers happy. 🙄

  • Bert says:

    I was going to be one of the people commenting on the original post. And after giving it a lot of thought this is my thinking on TailwindCSS.

    It is not a tool for beginners, not at all. It’s primary goal – the way I see it – is to constrain the usable scope of CSS. The inline classes is the “REPL” mode of tailwind, you should use the “`@apply“` approach for finished components.

    Is this a good thing? Maybe… I like it. It forces a consistency on designers & developers. Constraints usually help creativity, so that could be an argument as well.
    On the other hand it requires juniors to learn about TailwindCSS and css at the same time, which can be daunting.

    TailwindCSS is a CSS framework that reduces the scope of CSS. It is not a UI framework. That is where TailwindUI comes in. I don’t like TailwindUI.
    There is no mention of accessibility, there is no use of the “`@apply“ approach, nor is there any code to help with interaction (dropdowns etc…).

Leave a Reply

Your email address will not be published. Required fields are marked *