Tailwind as explained in their official website is 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.
As a beginner writing pure CSS was very good since it helped in understanding and memorizing the rules needed to achieve a specific layout. I had a lot of experience in doing this, however, none brought me the satisfaction and productivity boost that TailwindCSS has.
Tailwind has a very basic syntax.
Here is an example of how it looks like:
<figure class="bg-gray-100 rounded-xl">
<img class="w-32 h-32" src="/sarah-dayan.jpg" alt="" width="384" height="512">
<div class="pt-6 space-y-4">
<blockquote>
<p class="text-lg">
“Tailwind CSS is the only framework that I've seen scale
on large teams. It’s easy to customize, adapts to any design,
and the build size is tiny.”
</p>
</blockquote>
<figcaption>
<div>
Sarah Dayan
</div>
<div>
Staff Engineer, Algolia
</div>
</figcaption>
</div>
</figure>
Each class represents a CSS declaration. In the example above pt-6
represents padding-top: 1.5rem;
This will generate the following:
Tailwind has a myriad of benefits compared to custom CSS
Some of the things I found interesting about Tailwind are:
No need to leave your HTML code
Writing code in one place can be faster and more interesting other than jumping from files to files, this can help to focus more on the task at hand.
At times this may become messy especially when working on large projects.
Smaller Styles
Tailwind guarantees a consistent bundle size since utility class names can be shared between elements.
For unused CSS, Tailwind is paired with purge CSS this removes extra classes on the codebase.
Higher Productivity
Writing Tailwind CSS is much faster compared to writing CSS or CSS-in-JS. Text editors and IDEs automatically helps us with the autocomplete and formatting, however, in order to trigger the autocomplete we have to write the selectors and pieces of declarations.
In addition, variants in Tailwind have prefixes which can be added to classes, representing a specific CSS pseudo-class or custom plugins.
Consistency
Also, Tailwind has a lot of pre-built classes mainly for sizing and coloring, this will reduce or completely remove the need to implement a design system.
Customization
Developers can extend or modify classes in the tailwind.config.js
file. One can tamper right into Tailwind and can also add custom plugins , changes made will be reflected in the final stylesheet.
Inside this file, one can create normal CSS classes.
Tailwind Drawbacks
Some of the things I may disagree with Tailwind:
Readability
When a considerate amount of classes are added to an element, it may become daunting to read.
With correct component abstractions this can be easily solved.
Complex Animations
Archiving complex animations is very hard.
One would have to create a class for each element in order to use plain CSS, this will end up in doing more work.
Use of libraries can also be used to solve this.
Some CSS properties are not included.
My Final Thoughts
In my journey Tailwind has helped in increasing my productivity, reducing the bundle size of my apps and made me more consistent.
Although it may have worked well for me and many other developers, it doesn't mean it is the perfect solution for every project.
Us front-end developers as long as we guarantee maintainability, scalability, and performance, Tailwind is definitely the best solution considering its myriad of benefits.
Top comments (32)
Do we have a name for these types of libraries that use a bunch of classes to write less css? :)
My primary concern with these types of libraries are like you mention, the longer class definitions, and that they move the payload from the CSS onto the HTML.
Meaning even tho the library is smaller, the overall payload for a page may not be.
Personally i really like using the BEM + Atomic Design approach but with mixins for everything but atoms, that way each component is self contained, and when packaged i only get the used styles.
The douple definitions this generates, are then handled by strong gzip/brotli compression, meaning the overhead of the duplicate styles become insiginificant.
The increased productively is something i can agree to tho and is a big seller, not having to write styles seperately means a faster output. :)
My conclusion so far has been that BEM & Atomic design like patterns are good for established design systems, because consistency is easier, and you can do global design updates without running into issues where .pad-15 is defined as padding of 30px because we did not have time to update all the templates. :D
Outside of design systems, where consistensy is less important then making more parts fast, then i definitely see a good usecase for libraries like tailwind. :)
Same bruv, I also use raw css but follow the CUBE methodology. Really love exceptions in that. Amen to what you said!
Nice, never heard of CUBE before, reading about it now, and i am really liking the different perspective, thanks!
The magic everyone misses in these languages is @apply. You start with the classes, then you can build the classes that are just a merging of those classes. Start with classes, deploy with @apply.
Looked it up briefly, it looks a lot like @mixins/include in sass but without the output duplication.
I hope something like this makes it into the CSS spec soon'ish. :)
Yeah, the term is utility classes.
And the same principal that means CSS duplication is compressed away also applies to HTML with a lot of duplicate classes. If you have a lot of components with bg-blue-400 in your markup the same thing will happen when it's served compressed.
Tailwind works when you have a component system on the template/server side. It abstracts away the components so you're not continuously using the same long list of classes throughout the app.
This is true with gzip compression, do you think brotli makes a different with it's dictionary?
Also, wouldn't the purge mean we have changing css files, that cannot be re-used if we generate the css files per page?
We could purge per project, but then we still have more classes then needed, and scanning an entire site would require a lot of deeper integrations to work vs doing it per page.
How bad would this be without the purge?
I don't know a lot about brotli, but I have to imagine every compression algorithm uses tokens to replace reused content, otherwise it wouldn't be effective at all.
The CSS purge is site or app wide, not per page. This is what you want, because the number of unique classes doesn't keep growing and growing as an app gets bigger. A single CSS file then covers the whole app, and is usually much smaller than traditional CSS that has to grow to style more components and patterns throughout an app.
I just checked a few sites using Tailwind in production (not mine), and the CSS build sizes were:
Nice, thank you for taking the time to get these numbers. :)
Yes size gets moved to HTML, however, it is a fair tradeoff. Every HTML page that needs those styles, has them. The CSS then gets treated as a common import - with a finite size. The problem with other approaches is that there are often bad / changing categorisations of things when building. This results in duplication of CSS which is not easy to untangle.
What are you thoughts on CSS duplication being mostly removed with proper compression?
I'm also not sure what you mean by bad/changing categorizations, could you give an example?
Thanks! :)
The categorisation problem is the adage that naming things is hard. I have worked with designers and PM's who start with one design, and then cascade to many many variants without telling you in advance.
For example, say there is a component that only exists on the settings page - like a block of text above a group of buttons. You might start by calling the CSS container .settings-page as the block. Then you might call the text the .settings-page_text as block and element, then you might call the button group .settings-pagebutton-group, then you might call the individual buttons as .settings-page_button--primary to have block, element, and modifier.
Then your designer/PM likes the button group and wants to use it in a completely different page. You can no longer use the previous naming convention. This example is a bit contrived, but what I am pointing out, is that you can't always know in advance, how the naming should actually be for your usage. What you can know is that a button should be say primary and you apply the atomic style to style it primary.
Their own definition for tailwind is "Utility-First: Building complex components from a constrained set of primitive utilities." - which kind of feels appropriate to me :)
The main advantage of Tailwind over other frameworks like Bootstrap is its versatility. Have you tried switching from v3 to v5 Bootstrap? Elements have changed, naming has changed - with a large project it's a huge amount of work to check and rewrite. TW allows you to mix classes - you can put them directly into HTML code (great for all sort of components) but it also works beautifully with BEM using @apply and postcss. This gives You opportunity to create own elements and then easily switch even to pure CSS. I'm also using JIT compiler so build is fast and small in size.
Have you tried switching from v3 to v5 Bootstrap? Elements have changed, naming has changed --> because each version of bootstrap is a different framework and this is explicitly said in their doc. And this is actually a good point because if you want to change the version you have to change your thinking and adapt your site to the new standard. With tailwind you may never touch the code for a long period and one day when you want to change it you will get lost in the amount of class you wrote
Bootstrap also comes with a lot of utility CSS. Are you aware of this?
I agree that writing
class="flex flex-row justify-center align-center h-10 w-10"
may not be clear. But you must not forget that you can create a class composed of another class using "@apply".Like
class="myClass"
.myClass {
@apply flex flex-row justify-center align-center h-10 w-10
}
With a meaningful name for your class.
Loved the piece. Tailwind does comes with its pros and cons. BTW do give this piece a read if you are a Tailwind user like me: dev.to/msaaddev/tailwind-css-user-...
Also, this might also help you to eliminate the grunt work of Tailwind CSS setup: github.com/msaaddev/new-tailwind-app
Increased productivity is a subjective matter.
Tailwind is good for smaller apps, but as soon as the app becomes big; all of these classes become a nightmare to manage as compared to the BEM or atomic approach used while writing css/scss.
I had to quit Tailwind halfway in a project just because it was not manageable on an industrial level software.
Nice writeup, love how you talk about the pros and cons instead of blindly following the trend.
One aspect of Tailwind that's rarely discussed is its handling of complexity. Sure, it pretty much avoids specificity and therefore deals with one of the challenging aspects of CSS... but that also makes media queries quite hard to work with. You just keep adding classes and classes for each viewport size, which is a sub optiman solution.
In my opinion, this is going to be its downfall. CSS is getting increasingly complex in that direction. Media queries nowadays go far beyond screen sizes, into multiple accessibility issues such as dark mode, reduced motion, high contrast, etc. And it's about to become even more complex with container queries, layers, scopes... things that I can't really see Tailwind (or the utility-first / utility-only architecture) handling satisfactorily.
But that's me. In the very near future (~ 2 years) we may go into a valorization of the "normal" CSS specialist to handle the incredibly complex contexts of modern CSS. Or not. But if we do, Tailwind is going to be rapidly obsolete.
Everyone's preference is going to be different, just as we are all different. Personally I use Chakra-UI. After getting comfortable with it I can't hardly stand to see normal HTML, such as div's, in my code. ;)
I have tried to use Tailwind twice now but I keep returing back to standard CSS. I do have some Bootstrap components as foundation always but then the rest is just SCSS with BEM approach.
Problem with Tailwind is number of css classes I need to write. Often css class starts to look like style tag and I end up wondering how is this better and faster?
Perhaps I should give a third go to TW but then again, BEM with Atomic Design isn't really broken to me. So why try to replace it?
But if you use Tailwind, chances are you'll be standardizing raw CSS avoidance in your guidelines (otherwise your codebase would turn into a mess with the very first freshly hired frontend developer), so your cost to hire rises drastically, because you now have to teach every single frontend dev you hire how to use Tailwind? It's not nearly a no-brainer must-have like ES6, you can't only hire those who know Tailwind — there'll soon be no candidates to offer a job to.
I had to make that kind of decisions while working as a lead frontend dev / evangelist and interviewing 10 devs a week. Gulp broke on us and turned into legacy, same with SCSS and obviously Backbone.
Can't go wrong with raw tools though, considering the fast pace of innovation of web standards.
To me, Tailwind is only perfect when you’re writing code alone 😉
I tried many times but always end up writing raw css. So I'm a exception and this was not convincing. Just because I've heard same points many a times.