Tailwind: A Utility-First CSS Framework
tailwindcss.com
tailwindcss.com
You really do have to try it to shake that impression.
If you need a bit more convincing before you're willing to try it, I wrote an in-depth article a while ago that documents my journey from a "semantic classes"-loving HTML/CSS purist to a utility-loving heathen:
https://adamwathan.me/css-utility-classes-and-separation-of-...
If you want to watch it in action, here's a screencast where I rebuild the Netlify UI in an hour and a half without writing any custom CSS:
https://www.youtube.com/watch?v=_JhTaENzfZQ
...and if you want "social proof", here's an interview I did with Diana Mounter who leads the design systems team at GitHub about how moving to a utility-based approach has made things infinitely more maintainable for them, and given their developers a lot more confidence:
http://www.fullstackradio.com/75
If you have any questions I'll be checking the comments, thanks!
This is so true. All the classes in HTML source look so ugly and verbose when you first see it. At first I dismissed the framework and wondered how someone could think this was a good idea.
I kept seeing it pop up, and the comments were always positive, so I put in a little more effort into understanding how it works. Eventually I decided to try it, and within 5 minutes I was making stuff that actually looked nice. I used it to create a really minimal company website, that looks totally custom, and is really lightweight.
Thanks for sharing it, I really enjoy using it!
Then I also have to write our own classes for modals, cards, toasts, lists, media objects, drop down menus, side menus, breadcrumbs, buttons, forms, their labels, images and their captions, and get the right mix of responsive utility classes as well so they all play nice together.
I'd rather just pick a framework that lets me customize the corner radii, padding, margins, and be done with it.
With Tailwind, we don't try to pretend that you will never need to write any CSS, and instead embrace that fact and give you as much tooling and guidance as possible on how to extend the framework the way it was intended to be extended.
In the situation you're talking about, you would extract a "component class" using Tailwind's `@apply` directive to enforce that the component followed your design system:
https://tailwindcss.com/docs/extracting-components
Then you could update all your buttons at once by making changes to that component class.
The key with Tailwind is that it encourages a "utility-FIRST" workflow, not a "utility-ONLY" workflow. Build your UI with small primitive utility classes, and extract components only when you start to experience painful duplication problems.
Then you could update all your buttons
at once by making changes to that component class
Oh my god, that's genius!I'm looking forward using this right away.
First of all for the wonderful experience to add a class to my buttons. I think I will call the class "button". But I'm open for other suggestions at well.
Second for learning your DSL. Curious what other clever tricks you invented.
And most of all I am sure I will love implementing a compilation step into my workflow to turn your DSL into actual html and css. It always felt a bit too lean to just change a style and reload the page.
.btn {
@apply .bg-grey .rounded-sm;
} .align-left {
text-align: left;
}
This is a very reusable class, of course, because it is literally just css but with a different name. But that's what always ends up happening. The lowest common denominator for reusability in css is so low, that you often end up with ridiculously simple classes like this, or close, basically re-inventing css with a different syntax. The new challenge becomes learning this new language and how to compose it.The core issue with CSS is that it has divergent architectural characteristics simultaneously. On the one hand there are usually a set of extremely re-usable primitives: btn, normal-text, overlay, card, etc. Then very quickly, we get higher-level components/styles that are extremely not re-usable: order-form, contact-page, etc. And other stuff in between. Applying the same structural models to all of it will cause sub-optimality at some level.
To address this, I've found that applying different models to different aspects of the css most beneficial. Basically having a mix of both utility css, and semantic css. Low-level, highly re-usable components are defined in a utility fashion so that font-sizes, colors and other things are consistent throughout the site. And complex, non-reusable high-level components that compose primitives, and other custom non-reusable css, to define the top-level components. When the need for sharing common css arises, those can be abstracted out into utility stuff, but part of the goal is to keep the utility part small so that people don't have to learn an entirely new language.
[1] https://adamwathan.me/css-utility-classes-and-separation-of-...
Also, from a previous comment of mine:
“Problem is, defining quantity in the class name doesn’t work. .m10 may be fine for desktop but not for mobile. Then you’ll have media queries which define .m10 as margin: 5px or something, which is nuts. You could go for unspecified .mSmall etc, but in real life, things tend to be more specific and messier, in my experience.”
I'm experimenting with using 'em' and % everywhere, base font size with 'vmin' and scaling font size with %. Works pretty well for scroll-less apps.
Don't go overboard, but a little offset can go a long way
The solution is pointed above, even more classes for responsiveness.
You can easily do something like 'w-10 sm:w-5', and it'll add a media-query based class.
Keep up the good work!
For anyone building React apps with Tailwind or Tachyons, I just open-sourced a library that makes it easier to reuse CSS classes in standalone, customizable components:
https://www.npmjs.com/package/nanostyled
(I think this is a React implementation of what the Tailwinds docs call "Extracting Components".)
I was curious what your thoughts are on a JS-based functional CSS library? I noticed that you mentioned emotion on the docs, and that was also what I thought would be the perfect tool for the job
Imagine a set of functions like `textColor()` or `margin()` that return composeable objects that you'd stick onto css props, and just like tailwinds would throw errors or lint warnings if you didn't pass in values it was configured to allow? (E.g., colors.red, okay, colors.maroon, error? Or maybe colors('red') okay)
I figured it'd more elegantly solve the problem of generating stylesheets that are too large and then needs to be pruned off
One trade-off I see is that the utilities would need to be imported to each file that needs it (as opposed to strings you can put anywhere), but the the good thing about that is you could more easily click into the definitions that way, and you could namespace utilities under a variable so you'd only need to import one thing
I would guess you'd put more thought on this topic than I have, very curious to hear what you think
Not really :) It might have been my reaction some 10 years ago, but right now I think it's quite good. I've done BEM, the atomic crap, OOCSS and what have you but to be honest nothing beats composition when it comes to rapid development. I used Bootstrap in the past, it was heavily customised for the project, and I ended up making it look very similar to your approach. It makes sense when you have 20 Devs working on a website and you don't want to end up having separate stylesheet for every page. Because business hates consistent design and always wants this and and that to stand out just on this one page. It should be easy, right? I look at your framework as an embodiment of understanding business driven development in a big team.
* Define the essence of your design in a JSON - typography, colors, spacings, shadows, borders et al.
* Anyone in the team including backend developers can create new interface components without waiting on a designer, thanks to well-defined scales that compose well.
* The component (HTML+CSS) is the unit of abstraction. eg: "ProfileCard". Inside ProfileCard you'll use Tailwind's utility classes to build your component. You reuse this component everywhere, and if you have to "change a button's padding across the product" (which to me is far too rare) you open your component files and change them there.
* It is so easy to build UIs - you don't have to name every single element in the DOM - these names are _only_ to act as "hooks" into the CSS, and serve no abstraction. With Utility classes you can just assemble them in the HTML without touching the CSS
* Tailwind has excellent documentation and great conventions - this means between projects all you need to know is their particular scale. Don't have to learn a new UI framework everytime.
* Consistency, consistency! Thanks to design scales.
* Works so well for custom UIs. Have your designer do absolutely original designs in Sketch, and first transcribe their scales into tailwind.config.js, and voila! start pushing out its HTML at breakneck speed.
> Define the essence of your design in a JSON - typography, colors, spacings, shadows, borders et al.
_variables.sass
> Anyone in the team including backend developers can create new interface components without waiting on a designer, thanks to well-defined scales that compose well.
This is true, but is solved by any sort of component system and not unique to tailwind.
> The component (HTML+CSS) is the unit of abstraction. eg: "ProfileCard". Inside ProfileCard you'll use Tailwind's utility classes to build your component. You reuse this component everywhere, and if you have to "change a button's padding across the product" (which to me is far too rare) you open your component files and change them there.
Why would you change a padding in multiple files when you can set `$base_padding: 10px`?
> It is so easy to build UIs - you don't have to name every single element in the DOM - these names are _only_ to act as "hooks" into the CSS, and serve no abstraction. With Utility classes you can just assemble them in the HTML without touching the CSS
Going by the first example in the linked article, something like "text-grey-dark" seems like an awful idea when what it really means is "text-quiet". Heck in their example "dark" is _lighter_ than the surrounding text.
But you can even do BEM with Tailwind if you really want to with @apply.
> Why would you change a padding in multiple files when you can set `$base_padding: 10px`?
Neatly written CSS that uses variables for design scales are a good thing to have, but without any kind of tooling help, it is really difficult to keep it consistent. Tailwind on the other hand gives you the affordance for that - a "pit of success" because you never have to define magic values and instead use pre-defined functional CSS classes.
Regarding colors - you can use "text-quiet" or "text-title" etc. - the names are fully in your control and can be set in the configuration JSON file.
http://getbem.com/introduction/
In short, you do things like this:
.form { }
.form--theme-xmas { }
.form--simple { }
.form__input { }
.form__submit { }
.form__submit--disabled { }
Where the prefix __ is an Element and -- is a Modifier.
So, in that example you have the form, the form with Christmas modifier and also a form button that is expected to only happen under forms.
To me I still think that the good old "HTML describe how the content is organized, CSS describe how this content looks like" is the way to go. In the end it's how CSS and HTML were designed at first.
But when I see that
<div class="bg-white mx-auto max-w-sm shadow-lg rounded-lg overflow-hidden"></div>
I'm sorry but it just doesn't feels right to me. <div style="background: white">
with <div class="bg-white">
without realizing that the first is considered a bad practice for a reason and that the second is equivalent.Not quite, for a few reasons:
Inline styles don't respect media queries, which basically rules out responsive design
Inline styles aren't limited to pre-defined options, meaning you can still end up with 90 different shades of blue)
Inline styles cause specificity issues, since they trump separate stylesheets.
Inline styles don't support print-specific styles.
Inline styles can't address pseudo-elements (such as ::before and ::after)
Inline styles can't apply to multiple elements. Utility classes can define .bg-blue once and have it apply to many things, which leads to shorter markup and quicker rendering speed.
Inline styles are a pain to type. Compare class="f-sm bg-blue" to style="font-size: 10px; background-color: #0000ff;".
Utility classes fix all of these things.
But let's say there are 700 components, what's the alternative if we were using BEM? You'd have to change all the 700 CSS classes, breaking things everywhere thanks to cascades, inheritance, multiple selectors, and specificity. With Functional CSS, all you have to do is go to the markup, and change "bg-white" to "bg-offgrey", and nothing breaks.
I think the big shift started to happen when people started to say, let’s treat CSS like code and what would we expect of good code, and then all of these CSS Sacred Cows were then seen in a new light. The biggest of them all for me was ‘naming things are hard’, traditional CSS implies naming your classes is easy, and for a once off example it is always easy, but that approach is a lifetime commmitmnet to generating names on names just to add styles and this adds a naming things complexity burden that until recently has just been a generally unacknowleged invisible cost.
If you have 500 buttons using the exact same set of classes, you should of had a button class in the first place. Almost all my projects have their own button and form input classes for this exact reason!
Where utility-based CSS frameworks really start to shine is the other 75% of your codebase, where you're inventing clever class names, only to end up using them once.
This is also why Tailwind calls itself a utility-FIRST framework. Build things with utilities, and extract components to classes when the need arises. Avoiding early abstractions provides a lot of value (in any programming language for that matter). Not having to invent a name for every single piece of UI also saves a ton of headaches down the road.
It is crazy how new technology brings up old patterns again. Similar to how it was frowned upon to have JS near your HTML ("must be separated!") and now with React they are intertwined to a maximum.
I oftentimes find css to be the most complex and hardest to change part of web applications and am thankful to any approach that explores alternatives!
[1] https://adamwathan.me/css-utility-classes-and-separation-of-...
https://adamwathan.me/css-utility-classes-and-separation-of-...
Adam Morse, who wrote Tachyons a highly influential Functional CSS library, has written about this nicely with concrete data: http://mrmrs.github.io/writing/2016/03/24/scalable-css/
Most frameworks support some kind of re-use of CSS declaration blocks - use that feature to build your components from the primitives they provide, but also add a layer of indirection by putting those components behind a semantic class name. Voila, loose-coupling with all the productivity benefits of the frameworks.
<button class="login-button">Login</button>
.login-button { @apply .btn-primary; }
.btn-primary { @apply .font-bold .py-2 .px-4 .rounded; }All the benefits with none of the coupling. Tailwind might actually be pretty nice if used this way.
The practical dev workflow of using tailwind is a breath of fresh air.
Coming back to old projects with bespoke CSS is SO PAINFUL to edit/change compared to something built in Tailwind.
You absolutely also have the power to make css components/abstractions as well.
Tailwind is the only CSS framework I use since I discovered it and I'm gradually converting my/company projects to use it.
Keep HTML for HTML and CSS for CSS.
https://github.com/tachyons-css/tachyons
Its similar, but has been around since 2015.
The website themes just seemed so much simpler and minimalist, but also more consistent across the whole site. Significantly reducing the amount of time I need to create my own CSS classes.
"Steel" http://www.csszengarden.com/219/
Much more common, however, is overriding styles at the component level, which gets funky with this approach.
You either have to add JavaScript logic to assemble the appropriate class names or you wind up with a situation where elements have classes that conflict with their styles, because they are overridden. Imagine something with .text-purple, where the text is clearly not purple.
But let's remind everybody that this is only one approach of many you can use.
One approach that can solve problems Tailwind tries to is proper planning. An initial style guide can show you that the `author-bio` component looks similar to `article-preview` (taken from the author's blog post[1]), so you beforehand plan for that HTML and CSS and create a component you can reuse.
Of course, you could have decisions made after the fact and go back and change stuff; nothing is bulletproof.
- [1] https://adamwathan.me/css-utility-classes-and-separation-of-...
In the document case, it is possible to mostly keep the document semantic and apply styling via CSS. It matches the content/style separation well.
For web applications, I really like tailwind-like approaches, for multiple reasons:
* changing the style globally is probably hard anyway without adapting the HTML as well (as in the app case, often lots of other things depend on margins etc for example and you have a lot less uniformity/more special cases than in the document case)
* because there is less uniformity, the reuse aspect of the traditional content/presentation split is greatly reduced anyway
* web apps often use component based frameworks already, so you still get reusable components
This is something that went understated in other functional libraries, even though composition has been possible for years using preprocessors. So when people saw Tachyons, for instance, they would recoil at what they saw as an unmaintainable mess even though the underlying theory is sound.
I really like the work Adam is doing and where he is leading the conversation. I will read anything he writes, too. He's great at expressing his ideas and rallying you around things you didn't know you care about.
Small utility classes without writing CSS, seems like the same thing.
Disclaimer: I worked with the devs that created it.
So true.
That's why CSS-in-JS is awesome.
Everything is in one component, nobody cares anymore if you need to edit markup AND styles.
Really i don't need the compile-step, just really wanted to get out of the bootstrap canton
Some sample code on the doc site itself https://tailwindcss.com/docs/examples/cards/
For what it's worth, I don't think "What is Tailwind?" makes that clear (the "designed to be customized" section hints at it) and I had to read https://tailwindcss.com/docs/configuration to understand the difference after reading your comment. Thanks!
Are we missing a [1996] in the title?
It also means, for front-end developers like me, that I can create a company theme on Bootstrap, and get junior developers to use it can feel comfortable with being able to implement the brand design language and not have to pixel-fiddle. Not only does this strengthen the technical skillset of my team, but it also helps keep standards high when dealing with offshore resources.
We can get them to build UI for entirely separate projects, slap our branding on it, and dramatically cut down on resource allocation, time, and effort.
So, here's the thing: this is great, but Bootstrap also has utility classes these days. If I use Tailwind, or Foundation, or Bulma, I immediate lose out on developer leverage. This is so much more powerful than moving some classes around.
Approaching all of these design concerns in a slightly different way just isn't powerful enough to outweigh the leverage Bootstrap has over everything else out there.
It's just not significantly different enough. It doesn't standout to me. In fact, how it differentiates in its introduction is a _con_ to me. No, the industry doesn't need complete UI kits, design languages vary enough that this could provide additional undesired weight, however people use buttons, drop-downs, and many other common components _all the time_.
A major competitor to Bootstrap in the arena would need to do something revolutionary.
If you need to customize the components a lot you might lose most of the benefits that Bootsrap provides, that's where Tailwind comes in.
technically, it have all the themes to the point that picking up individual color for everything make it as unmaintanable.
5 years ago, it should had help some dudes but right now ... choose foundation/bootstrap/materialcss ... or build your own BEMized css ...