A deep-dive into Tailwind's surprising ideas hiding behind its unconventional syntax
Tailwind is perhaps the hottest CSS framework to come out of 2019. It's gotten not only a lot of hype, but a lot of criticisms as well. Its syntax can easily evoke some bad reactions from even the most experienced developers—including myself, to be honest.
However, I'm not one to dismiss things for simply looking different on a first glance. Remember how we all thought of JSX when it came out?
I set out to try to dive into Tailwind. Rather than focus on its eccentric syntax, I tried to find out what made it different... and I'm pretty blown away by what I found.
You may come across Tailwind examples that have cryptic class names in HTML. I can't blame you if snippets like these would seem wrong:
If this doesn't sit right with you, you wouldn't be alone. Not all developers prefer to use Tailwind in this way. For now, let's set this aside—lets look at the other Tailwind features that can help make cleaner markup.
Next: What else does Tailwind have other than a funny syntax?
Writing the class names out in HTML is only one way to use Tailwind. Here's another way to write the example above, writing CSS this time instead of HTML with PostCSS.
This works because Tailwind is, first and foremost, a PostCSS plugin. Tailwind can also be used without PostCSS, but that would be missing out on what I think is Tailwind's hallmark feature:@apply
.Next: What's so special about this feature?
The @apply
directive lets us compose CSS classes from other CSS classes. This, in my opinion, is one of the pillars of the Tailwind philosophy: CSS is easier to understand if it's broken into smaller pieces. Some CSS classes can easily end up being unreadable:
One way to make this easier to understand is to separate them into manageable chunks. Tailwind allows you to do just that.
Tailwind lets you build components from smaller pieces. They don't need to by Tailwind's utilities—@apply
will work on any class name. These pieces are called "utilities."Next: Aren't utilities just mixins in disguise?
This idea of utilities isn't new. Composable CSS is a concept previously explored as mixins by Sass and its cousins. In these pre-processors, you may commonly see mixins take parameters for extra flexibliity. The shadow-4
utility might look like this in Sass:
One key difference here is the Sass mixin is like a function that takes a depth parameter. This can't be done with utilities based on CSS class names.
While parametric Sass mixins can be more liberating, it can also introduce some problems. While the mixin above may let us write shadow(4px)
, it would also allow any value which potentially can lead to unexpected results. There are no restrictions to what parameters we can pass:
Next: Let's see how this might look like as Tailwind utilties.
Utilities in Tailwind are often written with a fixed set of values. This isn't as flexible as Sass's parametric mixins, and this rigidness is intentional. By hand-picking what values are allowed, designers can define the constraints of a design system.
Parameter-less utilities allow us to build design systems. The shadow mixin above may be expressed in a Tailwind utility like this:Next: Let's look at other features of the Tailwind CSS plugin.
One common way CSS files become unmanageable is writing some values more than once. It's quite common to use a value like a primary color across multiple rules:
Tailwind itself has a solution to make this easier. Values can be defined as theme constants. These constants can be used via the theme()
CSS function.
Next: Let's look at where these constants are defined.
The values for theme constants are stored in a Tailwind's JavaScript configuration file, tailwind.config.js
.
Placing them in JavaScript seems counter-inuitive at first, considering other solutions would have them in CSS files (eg, variables in CSS or Sass). However, having them written in JavaScript has a few advantages.
Writing the values in JavaScript allows us to use any kind of logic we may need. Need to have a shades of a color? We can use polished to adjust a color—no Sass functions or PostCSS plugins required.
Utility classes can be written in either CSS or JavaScript. Complicated logic doesn't have to be written with Sass loops or complicated calc() expressions—they can be written in JavaScript. For example, here's a rudimentary implementation of modular scale in Tailwind:
Declaring utilities and constants in JavaScript is liberating. Your CSS will be lightweight and declarative. The heavy-lifting can be done in JavaScript instead.
Next: Let's look at how Tailwind deals with margins and spacing.
Tailwind comes with a suite of CSS utility classes. They often come with preset values. For instance, the margin
helper can accept values like these below, which Tailwind calls this the spacing scale.
.m-0 | .m-px | .m-1 | .m-2 | .m-3 | .m-4 | .m-6 | .m-8 | ... |
---|---|---|---|---|---|---|---|---|
0 | 1px | 4px | 8px | 12px | 16px | 24px | 32px | ... |
You'll notice that the list above skips a few steps. There are no utilities available for m-7
and some other odd numbers. Tailwind is intentionally limiting what values are available to utilities.
By having constraints on possible spacing values, we are guided to a regular grid 4px grid. Tailwind makes consistency effortless.
Next: Let's look at what all this structure enables for us.
One common theme across Tailwind's features is how it establishes a lot of structure for us.
colors
, dimensions in spacing
, and so on.Next: What about preprocessors like Sass?
Tailwind can be used alongside Sass, Less, Stylus, and just about any CSS processor you can choose. Though it may be possible, it's probably a good idea to ask why you would want to. What are the benefits that Sass can introduce? More often than not, it would boil down to these features:
Most of these problems can be solved by Tailwind's PostCSS plugin—no other preprocessor required. Tailwind can make Sass redundant.
Problem | Sass's solution | Tailwind's solution |
---|---|---|
Color palette | Variables | Theme constants |
Spacing | Variables | Theme constants |
Components | Mixins | Utilities |
Shared utilities | Mixins | Utilities |
Tailwind is much more than its syntax may lead you to believe. It's a utility-first philosophy, a foundation for a design system, and overall a modern way to write CSS in the age of React and dynamic frontends.
Do give Tailwind a try. If you end up using it, then that's wonderful. Otherwise, I hope its ideas would help influence the way you look at CSS.