Introduction to Tailwind CSS and utility classes

If you haven't checked out Tailwind CSS yet or don't know what all the buzz regarding utility classes is all about, this article is for you. We'll take a first look at the advantages and get our hands just dirty enough to know what makes Tailwind a great CSS framework and what alternatives there are.

In general when talking about utility classes, you can think of primitive utilities that don't do much individually. In fact they shouldn't do much by themselves but work well when combined with other utility classes. The goal is to have a set of pre-existing classes that we can use to style HTML without writing a lot of custom CSS, which allows us to move faster and re-use those classes as much as possible.

Keeping it simple

We'll keep it simple and skip all the build-steps and setting up our tooling for now, even though it's an important and powerful part of Tailwind's magic. For now we'll just look at the concept of utility classes and see how they can help us reduce the required amount of custom CSS and allow us to style our content faster overall.

So instead of setting up a build step, we'll start by simply requiring the Tailwind stylesheet into a blank HTML file. That's all we really need to get going.

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" />

Let's start by looking at a <button> element and make it pretty! First, let's make sure it has a background-color —> In Tailwind we get a lot of predefined background colors, all created with rgba values, which allows our utility classes to change the colors based on the alpha, which we can set with a simple number in our class names like this:

<button class="bg-blue-700">I'm a button</button>

In this case, 700 sets the alpha and we can go lighter and darker from 50 to 900, where 50 is the only smaller step and the basic rule is that we can increase or decrease the alpha in hundreds. So if we wanted a lighter blue, we could set it to bg-blue-500. This is great, because it already gives us a clue how we can make use of this for our hover effect! Let's check that out.

In order to give our button a lighter blue on hover, we'll use one of Tailwind's prefixes: hover: and combine it with the background, we've just used above: hover:bg-blue-500

Sweet! We have a button that changes its background color on hover! Let's improve it further, by adding a font-color that is easier to read on our blue background. Just like we set the background-color, we can use the class text-<color> to set a color on our element. Again like the color palette for backgrounds, Tailwind comes with a set of predefined text-colors which can be adjusted by changing the alpha of the base color.

<button class="bg-blue-700 hover:bg-blue-500 text-white">I'm a button</button>

Side note: When using build tools we can also define our own colors, so we are not limited to the predefined palette.

That's a pretty rad button already and we were pretty fast to get there. This simple button element already illustrates how utility classes can save us a lot of time, as we have written exactly zero CSS so far, even though we changed the background color, text color and added a hover effect. And we're barely scratching the surface – let's dig a little deeper.

Digging a little deeper

I'm a sucker for details when it comes to user interactions, so I'm already having a hard time looking at the button we just created. It needs a transition! Luckily Tailwind has our back and we can make use of multiple transition properties, or go with the transition-all property, which defaults to the following.

transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;

Making sure we adhere to best practices around the reduced-motion property, we can even use a prefix called motion-reduce: to only show the transition when reduced-motion is not activated. Let's put that together real quick:

<button class="bg-blue-700 hover:bg-blue-500 text-white transition-all motion-reduce:transition-none">I'm a button</button>

At this point you probably got the underlying idea of utility classes, utilizing a standardized way of naming with prefixes, the actual class and predefined and adaptable modifiers: {prefix}:{class}-{modifier}. One downside people complain about a lot with this expressive approach is that we're overloading our HTML that way and it actually becomes pretty unreadable. It's definitely a good idea to start formatting your HTML a little more according to that and let lines not run too long. The alternative however is probably a rather lengthy stylesheet, so there are always trade offs 🤷‍♂️

<div class="..."
   id="...">
  Heya!
</div>

Before wrapping up, let's take a look at the bigger picture of building sites with Tailwind: Layout, spacing and responsiveness. Tailwind comes with a ton of handy classes to support us in all those areas like floats, flexbox and positioning classes, allowing us to build more complex components and layouts quickly. Let's take a look at a classic horizontal navigation bar using flexbox and centering things inside.

<nav class="flex justify-between items-center px-16 bg-blue-700 text-white h-14">
  <h1>Navigation</h1>
  <ul class="flex justify-between w-56">
    <a href="#">
      <li>Link</li>
    </a>
    <a href="#">
      <li>Link</li>
    </a>
    <a href="#">
      <li>Link</li>
    </a>
  </ul>
</nav>

There's a demo below the article.

Now that wasn't too much to write and we got a pretty solid navigation bar! If we wanted to change things on smaller or bigger devices, we can make use of prefixes again. Tailwind, much like Bootstrap, comes with predefined breakpoints (media queries) that are named as follows:

  • sm 640px
  • md 768px
  • lg 1024px
  • xl 1280px

Those can be seen as replacements for media queries in your CSS and when introducing them, the unprefixed version we have used so far will only be applied above the prefixed version. So if we were to use a class with the prefix md:bg-blue and also have a class bg-yellow applied to the same element, the background would only be blue for everything above 768px (md) and yellow below that breakpoint.

Just like predefined breakpoints, Tailwind comes with a set of spacings for paddings and margins that can be applied to either one or multiple sides of an element, basically making it a great alternative to margin-top: x; and similar declarations. All spacing adhere to the following syntax m{t|r|b|l}-{size} which translates to a class like mt-8 for a margin top of "8", where 8 translates to 2rem. Those values are as mentioned predefined but can be adapted when using a real build step. It's definitely worth checking out the Tailwind documentation for exact values and in general a good idea to get a more in depth understanding of everything described in this article.

Next steps and alternatives

A lot of the advantages of Tailwind actually come from using a build step and creating our own configurations. This step allows us to define new colors, spacings, fonts, and much more! It's like keeping all the benefits of the utility-first approach but making it your own and adjusting it to your design and requirements. A lot of people seem to skip this step, which is why we see a lot of sites out there these days that use the default Tailwind styles. Don't get me wrong – that's not a bad thing! But you are missing out when not making use of those customizations. In fact, I think it is so important, I want to dedicate another full article to customizing Tailwind.

In the meantime, there are also other utility-first frameworks that came before Tailwind and there will probably be a bunch more to come. Here are some really interesting ones I recommend checking out.

https://basscss.com/

https://tachyons.io/

https://yogurtcss.netlify.app/

https://tedconf.github.io/shed-css/index.html

https://turretcss.com/

And lastly, here's a working demo to play around with, which contains the basic examples shown in the article.

CSS
design
tailwind