This blog is all about CSS, but before you close that browser tab (I can see you there), it’s actually about how you can use considerably less CSS and achieve excellent results to boot.
What is the miracle technology that I’ve stumbled upon that allows you to create consistent-looking interfaces that adapt to different screen resolutions, and cut down on curly-braced spaghetti clutter that is CSS? It’s a clever little CSS framework called Tailwind CSS.
What is Tailwind CSS?
Tailwind CSS is, in their own words (from their website)
A utility-first CSS framework packed with classes like flex, pt-4, text-center and rotate-90 that can be composed to build any design, directly in your markup.
In other words, it’s a framework that wraps most CSS statements into helper classes that can then be applied to an app’s’ HTML instead of writing custom CSS for every single HTML element on the page.
The Tailwind CSS approach is quite a departure from orthodox front-end developer thinking, where for many years the consensus has been to write structured CSS that relies on well-defined naming conventions such as those found when following the Block-Element-Modifier (BEM) pattern or Object-oriented CSS (OOCSS).
The goal of BEM or OOCSS naming conventions is to convey structure and meaning to styles defined in CSS, but these structures can often lead to deeply nested and unwieldy CSS, especially if you use CSS preprocessors like Sass/SCSS that allow you to physically nest CSS into a never-ending field of curly braces.
Worse still is CSS that has been defined with ad-hoc naming conventions. These stylesheets can become so complex that even the original author of the styles may become confused about the intended styles when modifying or adding to the styling of a web page.
Tailwind CSS avoids the problem of complexity by providing utility classes that can simply be added, mixed and matched with other classes inside of an HTML elements class attribute, preventing the need for complex naming or deep nesting.
So, it’s another component library?
Not quite. Tailwind doesn’t give you pre-styled components like buttons, sliders or cards, it instead gives you a set of utility classes that closely map to CSS statements (such as display:flex, margin: auto etc), and provides a neat way of managing colour palettes and typography that allow you to reference them purely as utility classes in your HTML.
Tailwind CSS differs from many other frameworks because:
It doesn’t impose any kind of opinionated style or design language in your app, quite the opposite.
It gives you the tools to roll your own styles and keeps them consistent through the use of utility classes.
It is a very focused library that makes it simpler to create consistent theming in your app, but it doesn’t impose any kind of restrictions on how that theme should look.
Tailwind’s approach is quite a departure from other UI libraries like Bootstrap or Angular Material. These libraries provide a multitude of pre-styled components to use, but as a consequence somewhat lock you into samey and generic-looking UI’s that can often be quite difficult to customise.
My initial scepticism
When I was told about Tailwind CSS, I was very dismissive that it would make life easier.
I asked myself “why would you want to bloat out the HTML with a stream of never-ending classes? That sounds horrible”. But when I gave it a try I was shocked at what I found.
Time to experiment
I decided that I needed to give Tailwind CSS a fair try and see whether the claims made on the Tailwind CSS website hold up to the scrutiny of a front-end developer who’s familiar with the benefits and drawbacks of CSS.
As luck would have it, the annual Amplience hackathon, with the topic “present something that could improve Amplience in any way”, was about to begin.
Amplience encourages developers to participate in 2-3 day long marathons to explore ideas in a free-form environment and to find ways to make use of these ideas to improve Amplience products. These ‘Hackathons’ are a real blast and they allow us explore ideas which may not fit into our regularly planned work.
My gut feeling was that cutting down UI development time, and making the theming and styles of our products more consistent and maintainable, fit nicely into the goals and the spirit of the hackathon. So I got to work.
The Hackathon
On the first day of the hackathon I had a clear idea in my head of what I was going to build. I decided that I was going take existing UI components from Amplience apps and rewrite them using Tailwind CSS classes, to vastly reduce or eliminate the need for writing any custom CSS.
I decided on my success criteria:
The HTML must be easy to read, even with the extra Tailwind CSS classes.
CSS in each component should be minimal. The odd statement here and there is fine, but if I’m unable to find what I need as a utility class, then that will be a mark against Tailwind CSS.
The UI components I write should not look vastly different visually from the originals, within reason.
The developer experience must be pleasant and frictionless. There’s no point adopting a new tool or framework if it’s unwieldy to use. Using Tailwind CSS should be a help not a hindrance to my workflow.
So I got to work writing components using Tailwind CSS and these were my findings.
Readability of HTML using Tailwind CSS
Adding utility classes to HTML instead of writing custom classes did not make the HTML any less readable. On the contrary, I think it made it more readable. I didn’t have to context switch between reading HTML and looking in a CSS file to see styles anymore.
To my surprise, I didn’t need to add that many utility classes to each component to get the job done, so Tailwind CSS passes my first test.
1<!-- Tailwind CSS utility classes can be seen in the class attribute 2of the button element below 3--> 4<button 5 type="button" 6 class={`${colourScheme} font-sans mx-1 my-0.5 px-2 transition-colors leading-6 text-xs rounded-sm`} 7 on:click={onClick}> 8 {label} 9</button>
How much CSS I still had to write by hand
For the most part, I was able to implement the UI components using purely Tailwind CSS, Most of what I needed was provided as a utility class. I was able to set margins, padding, flexbox properties and even hover and focus states on the components using Tailwind CSS utility classes.For typography and custom colours I did have to make changes to the Tailwind CSS config files, but this is the intended purpose of the config files, and helps to ensure that your typography and colours remain consistent throughout the app.For the odd thing here and there I did need to add my own CSS, but this was incredibly rare. In each case I could have probably found a decent analogue class in Tailwind CSS given more time.1 // an extract of the Tailwind CSS config file. Note the definition of custom font and 2 // custom colours 3 extend: { 4 fontFamily: { 5 'sans': ['Roboto'] 6 }, 7 colors: { 8 orange: { 9 500: "#ff3e00", 10 }, 11 blue: { 12 500: "#039be5", 13 900: "#17202c", 14 }, 15 gray: { 16 500: "#e5e5e5", 17 800: "#29333f" 18 } 19 }, 20 },
Consistency of UI components compared to the originals
I am mightily impressed with how close I was able to get the components to look compared to the originals. Tailwind provides utility classes for hover and focus states. This greatly simplified implementing the complicated nested CSS structures of the originals as a combination of Tailwind CSS utility classes.
The components were not 1:1 clones of each other, mainly because Tailwind defined most of its margins, padding and other spacing properties as REM units.
Tailwind CSS uses REM units to scale the UI relative to a user’s base browser font size. The benefit of this is that the user can adjust their base font size and the other non-text elements will scale accordingly. This is great because you get out-of-the-box accessibility for any users of the website that rely on bigger text in order to read it clearly.
The original components that I based mine on are styled in CSS use pixel units, and it’s not possible to use pixels in Tailwind CSS. You do need to break out and write custom CSS if you need pixel-perfect precision, but it does go against the spirit of using Tailwind CSS in the first place.
Overall I was happy with the consistency of the components I wrote. I think that if you wrote an entire app in Tailwind CSS and with a Tailwind CSS mindset, you wouldn’t even worry about buttons or other elements being ‘pixel perfect’, they’d just look right and in proportion to everything else in the app.
Developer experience
The ease of development using Tailwind CSS exceeded my expectations, although it was not exactly without its drawbacks.
Adding the utility classes to the HTML was very straightforward and the utility classes had sensible names that mapped closely to the names of the CSS statements.
To my surprise, I felt like I had to add way fewer utility classes to elements than I had ever expected. My fears of code bloat in the HTML and repetition were put to rest very quickly.
Choosing the correct helper class was sometimes a case of experimenting as the names of margin helpers, for example, do not map directly to their CSS definition. ( class m-1 maps to an all-round margin of 0.24 rems). Let’s be honest, you’re not going to know what that looks like until you put it down in the markup and take a look at it.
I also had a lot of trouble remembering the flexbox justification and alignment utility class names. In CSS I would write something like align-items: center, but in Tailwind the name of the utility class was items-center. I kept typing align-center and then wondered why nothing had changed.
I’m sure in time I would memorize the utility class names, but it’s quite laborious flicking back and forth through the Tailwind CSS docs to learn something you already know in CSS.
With all that said, not having to worry about ever-growing CSS structures was a pleasant experience and adding the utility classes provided by Tailwind CSS was fairly simple. The only complication was my lack of familiarity with the framework.
The final result
By the end of the hackathon, I was able to create faithful recreations of UI components used in our products.The take-home from all of this is that Tailwind CSS is a great framework for reducing the unnecessary complexity of CSS in applications.
There is a learning curve for memorizing all the utility classes and you’re probably going to need to change the way you coordinate with your designers and QAs if your team is orientated towards building UI components with pixel-perfect precision.
I found that the utility classes did not bloat the HTML that much at all, provided that the UI was already split up into smaller, more manageable components using a frontend library such as Svelte or React. It’s also very surprising how few utility classes I needed to use in each component.
While I didn’t win any prizes at the hackathon, (the competition was very strong and there were some amazing entries), it did give me the confidence to go all in on Tailwind on our next project, which I think is a great result in itself.
Should I use Tailwind CSS in my next project?
I'm sure you’re wondering by now, should you use Tailwind CSS in your projects instead of plain old CSS?
I would recommend you should certainly give it a try, especially if you’re starting a new project from scratch.
I don’t think Tailwind CSS will eliminate the need for custom CSS, but it will reduce the custom CSS footprint in your app and will make the CSS you do write more intentional, less repetitious, and not as complex as it might have been if you didn’t have Tailwind CSS doing the heavy lifting for you.
So, what are you waiting for? Give Tailwind CSS a go and see how it shapes up for you!