Christian Kilb

Tailwind

... and a brief history of CSS

Tailwind CSS is a utility-first CSS framework that provides a comprehensive set of pre-defined classes, enabling developers to quickly build modern and responsive user interfaces.
It focuses on simplicity and customization by offering a low-level approach to styling components.
This blog post will explain Tailwind's approach in a way I wished it was explained to me.

Once upon a time there was no CSS

When I started with web development in my early teenage years, CSS wasn't a big deal. While it was released in 1996 already it took a while to get widely adapted.

Website layouts were basically built with <table> tags and HTML attributes like color, bgcolor, cellpadding and so on.
Back then HTML source code looked similar to this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
    <table>
        <tr>
            <td align="center" colspan="2">
                <a href="/"><font color="red" face="Verdana">My website</font></a>
            </td>
        </tr>
        <tr>
            <td>
                <u>SIDEBAR</u><br /><br />
                <a href="/foo">Foo</a><br />
                <a href="/bar">Bar</a>
            </td>
            <td>
                <h1>Foo</h1><br /><br />
                <font color="#00008b">Lorem ipsum</font>
            </td>
        </tr>
    </table>
</body>
</html>

JavaScript was mostly used to apply some questionable effects to the mouse cursor - and to annoy people with popups and alert messages preventing you from leaving the website.

Popular software to write HTML code was Macromedia Dreamweaver and... my personal favorite... Frontpage Express.

Actually, things were quiet simple back then...

If you are old enough to remember these times, let us take a brief moment of introspection, shall we?

No SPA frameworks, preprocessors, package managers, dependency hells, super-feature-rich web browsers...

All the things we needed for web development were a simple text editor and an FTP upload tool...

...

Internet Explorer 6 Compatibility

OK, enough.

We would not be where we are today if the WWW and it's technologies haven't evolved.
Nowadays there are fancy E-commerce platforms, great games and billion-dollar enterprise applications running in a browser - no matter what operation system you use. That's actually a great thing and would not have been possible without the tools we have right now.

Then there came CSS... and inline styles

During the years the functionality of CSS increased, web browser got better in supporting it and therefore it got increasingly widespread.

While it was already possible to put your CSS stylesheets in a separate file or <style> block it wasn't too uncommon to simply use inline styles.

So this...

<font color="red">my text</font>

simply became this:

<span style="color: red;">my text</font>

The implementation of a linked navigation may have looked like this:

<nav>
    <ul style="list-style-type: none;">
        <li style="padding: 5px; ...">
            <a style="text-decoration: none; color: darkblue; ..." href="...">Foo</a>
        </li>
        <li style="padding: 5px; ...">
            <a style="text-decoration: none; color: darkblue; ..." href="...">Bar</a>
        </li>
        <li style="padding: 5px; ...">
            <a style="text-decoration: none; color: darkblue; ..." href="...">Hello</a>
        </li>
        <li style="padding: 5px; ...">
            <a style="text-decoration: none; color: darkblue; ..." href="...">World</a>
        </li>
    </ul>
</nav>

You can see, we have a lot of duplicate style information here. This basically had two downsides:
- Your HTML code got bigger, so it may be slower to load (We come to that point later again)
- If you want to change the style for multiple elements of the same type you had to touch all the places.

So, developers quickly agreed to use CSS classes instead...

Semantic HTML & CSS

When you decide to use CSS classes instead of inline styles you have to think about names for them.
There is the common approach to have your HTML structure as semantic as possible. That's good for crawlers - because for machines structured, semantic HTML code is better to understand - and has evidential a good effect to search engine rankings of the website.

To have good CSS class names & keep your HTML code semantic, the idea came up to give your CSS classes a semantic name, too. So, the naming of classes should not describe the styles itself (like "text-red", "btn-blue" etc.) but the element the classes are assigned to (like "sidebar"). CSS classes should only be used when necessary, to not clutter the code:

<nav class="sidebar">
    <ul>
        <li>
            <a href="...">Foo</a>
        </li>
        <li>
            <a href="...">Bar</a>
        </li>
        <li>
            <a href="...">Hello</a>
        </li>
        <li>
            <a href="...">World</a>
        </li>
    </ul>
</nav>
<style type="text/css">
    nav.sidebar ul {
        list-style-type: none;
    }

    nav.sidebar ul > li {
        padding: 5px;
    }

    nav.sidebar ul > li > a {
        text-decoration: none;
        color: darkblue;
    }

</style>

This was and still is considered a clean way to structure your HTML and implement your CSS classes.
The approach has a big downside though:
In bigger projects, the nesting level of CSS classes gets quite high.
High nesting levels not only make your CSS hardly readable - it's also way harder to maintain it: If you are required to change the structure of your HTML later on you have to adjust the CSS code to the new structure.
Superset languages on top of CSS - like SCSS - make your CSS, even with higher nesting levels, more readable to some degree - but they don't fix the actual problem.

I've worked on several dozen website projects that time.
How many projects do you think were strictly implementing semantic HTML and CSS?

?

?

Right. Zero.

The time and effort to "keep it clean" in a semantic way was simply not worth it.

Of course there are other approaches to have a clean CSS structure.

A popular one is BEM, wherein you don't try to keep the number of CSS classes as low as possible but instead classify every element you want to have a style into blocks, elements and modifiers.

<nav class="sidebar">
    <ul class="sidebar__list">
        <li class="sidebar__list-item">
            <a href="...">Foo</a>
        </li>
        <li class="sidebar__list-item">
            <a class="sidebar__list-item-link href="...">Bar</a>
        </li>
        <li class="sidebar__list-item">
            <a class="sidebar__list-item-link href="...">Hello</a>
        </li>
        <li class="sidebar__list-item">
            <a class="sidebar__list-item-link href="...">World</a>
        </li>
    </ul>
</nav>

BEM makes sure that the nesting level doesn't get too deep. Every element is inside a block and can have multiple modifiers. That's it.

Still, there are some downsides.
First of all it's not always clear what should be considered a block or element.
Secondly - as you can see in the example above - we again have a lot of code duplication again. Instead of style attributes we now repeat CSS class names instead.

For sure BEM is a nice approach and for many cases superior than inline styles.
But isn't it a bit frustrating to have to decide between code duplication and crazy nesting levels?

Well, there's an alternative approach. And it's actually so obvious that I wonder why no one really came up with it before.
Tailwind CSS is implementing this new appraoch, even though - in the past - the author of Tailwind himself initially did praise semantic CSS.

The Tailwind approach

The idea behind Tailwind is to not reuse CSS class names (even though it's possible), but to reuse your HTML code.

Let's forget about CSS classes again and have another look at our navigation with inline styles:

<nav>
    <ul style="list style">
        <li style="the same item style">
            <a style="the same link style" href="...">Foo</a>
        </li>
        <li style="the same item style">
            <a style="the same link style" href="...">Bar</a>
        </li>
        <li style="the same item style">
            <a style="the same link style" href="...">Hello</a>
        </li>
        <li style="the same item style">
            <a style="the same link style" href="...">World</a>
        </li>
    </ul>
</nav>

The issue here is not only the duplication of the style attributes but the duplication of the very same HTML tags again and again.
Even if you use CSS classes for every element you may need to touch every single element later again if the changes you want to make have to be done in the HTML.

So what we could do instead is to create several template files

navigation.html:

<nav>
    <ul style="list style">
        {% include 'navitem.html' with {'href': '...', 'text': 'Foo'} %}
        {% include 'navitem.html' with {'href': '...', 'text': 'Bar'} %}
        {% include 'navitem.html' with {'href': '...', 'text': 'Hello'} %}
        {% include 'navitem.html' with {'href': '...', 'text': 'World'} %}
    </ul>
</nav>

navitem.html:

<li style="item style">
    {% include 'link.html' with {'href': href, 'text': text} %}
</li>

link.html

<a style="link style" href="{{ href }}">{{ text }}</a>

Now, your CSS styles actually are being reused - but instead of just reusing CSS class names you reuse atomic HTML templates that contain CSS classes.

If you are using popular Single Page Application Frameworks like Vue.JS, React or Svelte, it is already quite common to split your HTML (and it's corresponding JavaScript) into several components. And it's a good approach to do that very granular.
But also for classic template engines like Twig it's perfectly doable to split your HTML code into several small components.
Actually the examples I just showed you were implemented in Twig.

So why not use just inline styles but a framework like Tailwind CSS instead?

Downsides of inline styles

Inline styles have a few downsides:

Tailwind provides you a huge number of CSS classes that work similar to inline styles but eliminate the downsides just mentioned.

Tailwind Example

While Tailwind class names are most likely still more verbose than those of other languages, it's much less verbose than inline styles.

Instead of...

<a style="display:inline-block; color: red; font-weight: bold; padding: 4px;" href="{{ href }}">{{ text }}</a>

... it will look like this with Tailwind:

<a class="inline-block text-red font-bold p-1" href="{{ href }}">{{ text }}</a>

Tailwind Media Queries Example

Tailwind enables you to use media queries.
If you want to implement a grid that shows 1 column per row on mobile, 2 columns per row on tables and 3 columns per row on bigger screens you can do like this:

grid.html:

<div class="grid grid-cols-12 gap-2" >
    {% include 'griditem.html' with {'content': 'foo '}%}
    {% include 'griditem.html' with {'content': 'bar '}%}
    {% include 'griditem.html' with {'content': 'baz '}%}
    ...
</div>

griditem.html:

<div class="col-span-12 md:col-span-6 lg:-col-span-4">{{ content }}</div>

CSS class configuration

Tailwind enables developers to follow a consistent style guide.
For example, if you Styleguide has a fixed list of colors that can or should be used in your design, you can adjust your Tailwind configuration file so Tailwind will automatically provide CSS classes for these colors. By default, Tailwind provides already a huge list of predefined colors - but if you like you extend or replace them.
This does not only work for colors but nearly every CSS attributes you can imagine.

Performance

In early times it was considered good programming style to have your HTML code as small as possible.
Compared to semantic CSS the Tailwind approach definitely bloats up your HTML a bit.

A small HTML file size is not important anymore though because of several reasons:

Downsides of Tailwind CSS

Now that you know about the idea and benefits of Tailwind CSS I don't want to keep quiet about it's downsides.

Verbosity

As mentioned before, your HTML tag class attributes can and will be quite long when using Tailwind.
Lines like this will be no rarity.

<button class="inline-block py-3 px-5 bg-gradient-to-b from-yellow-500 to-orange-400 font-semibold text-white rounded-lg md:hover:scale-110 transition-all duration-300" ...>

If you really do not want to have such thing in your HTML, you could move the list of classes into another CSS file and combine it into a single one.

.primary-btn {
    @apply inline-block py-3 px-5 bg-gradient-to-b from-yellow-500 to-orange-400 font-semibold text-white rounded-lg md:hover:scale-110 transition-all duration-300;
}

It's questionable though if this makes your code easier to understand if you have to look into several places (.html + .css file) to understand the implementation of your element's layout.
If you keep your (HTML) components small, having a few long lines of class lists might not be such a big deal breaker anymore.

You have to learn it first

Tailwind consists of a huge number of CSS class names that are only more or less loosely based on the CSS attribute they work with.
margin is m in Tailwind. padding is p, transform: scale(n) is scale-n and so on.

This is a bit of an entry threshold. To work productively with Tailwind from the beginning (and probably later on, too) I strongly recommend to have an extension (VsCode or IntelliJ) installed that will help you with autocompletion.
It might be also helpful to have the official Tailwind documentation open in a browser tab so you are able search for CSS attributes and find the corresponding Tailwind class.

Contact me

Christian Kilb