I'm a professional PHP, Python and Javascript developer from the UK. I've worked with Django, Laravel, and React, among others. I also maintain a legacy Zend 1 application.
I'm a professional PHP, Python and Javascript developer from the UK. I've worked with Django, Laravel, and React, among others. I also maintain a legacy Zend 1 application.
No, it isn't, any more than an approach like BEM is. You're still using classes for styling, but the scope of those classes is generally reduced a little. It's definitely not a one-to-one relationship between Tailwind classes and single CSS rules in every case. And, by using the @apply directive you can easily extract the styles used to a stylesheet.
Fundamentally Tailwind is an abstraction over CSS that provides the following benefits:
Limits you to a predefined palette of colours, proportions and so on. You can change this palette if it restricts you, but by limiting the scope of what classes are available for styling, it helps to ensure a greater consistency in your application - for instance, you won't end up with Alice using 3px for padding, Bob using 4px and Chris using 2px
Provides consistent modifiers for things like media queries (including dark mode) and state such as focus or hover. Inline styles can't do that
Makes it much less likely CSS rules will grow out of control. By encouraging use of the predefined Tailwind classes and discouraging making your own, it makes it easy for tools like PurgeCSS to strip out unwanted styles, resulting in typically smaller CSS bundles in the production application.
It's a particularly good fit for component-based JS libraries like React or Vue where you're actively encouraged to extract common UI sections to their own component. In that context it tends to be extremely quick to style it using Tailwind once you get up to speed, making it extremely useful for prototyping. Further into your project, once you have some styles established, then if you want to reuse them in ways that template partials or separate UI components don't facilitate, then it's easy to use the @apply directive to extract common styles and create your own more conventional classes, without losing the advantages of consistency mentioned above.
Honestly, I thought the same at first and it took a while for it to click, but I'd never go back. I maintain a big legacy project with a huge pile of messy CSS that I inherited and is very difficult to strip out. That would be virtually impossible for that to happen with Tailwind.
It's definitely not a one-to-one relationship between Tailwind classes and single CSS rules in every case.
That's not the important part though. Whether you're using classes or inline styles, even if one lets you do more things with less typing, the fundamental difference is that you are inlining the actual styling into your HTML.
There may be a CSS document somewhere that defines some more powerful tools in the form of classes, but those aren't styling "rules" in the same sense as with normal CSS; they end up being more similar to CSS properties, in that they just toggle atomic design elements like a colour or the text alignment.
The actual styling is still in your HTML though, so no, it is just plainly wrong to claim utility classes are somehow fundamentally different than inlining CSS using the style attribute. They may be more powerful and convenient, and that might for many be the deciding factor as to why this approach is okay to use while inline CSS is evil; but some sort of defense has to be made. One cannot simply claim that "they're different things" and dismiss all criticism of inlining styles into HTML.
There's a separate discussion to be had about whether enough of the problems with inline CSS aren't present, or whether the most relevant ones still remain, and that discussion can be a lot more nuanced and ultimately up to personal preference and picking the right tool for the job.
I'm a professional PHP, Python and Javascript developer from the UK. I've worked with Django, Laravel, and React, among others. I also maintain a legacy Zend 1 application.
The @apply directive renders much of that moot, though, since once you've settled on a style that works you can easily use that to extract common patterns into reusable classes. It depends on the context you're using it in, and for using component libraries like React it often makes less sense, but certainly if you're using Tailwind in something like Blade or Twig templates then using @apply is more commonplace.
I'm a professional PHP, Python and Javascript developer from the UK. I've worked with Django, Laravel, and React, among others. I also maintain a legacy Zend 1 application.
No, because Tailwind still works as an abstraction layer. And you can combine the two approaches however you see fit - it doesn't have to be either everything using the utility classes direct or everything using the apply directive.
It's like JSX in that it sounds arse-backwards when you first hear about it, but if you try it then once you get over the hump it starts to make a lot more sense.
I'm a selftaught (web) developer. On sunny days, you can find me hiking through the Teutoburg Forest, on rainy days coding or with a good fiction novel in hand.
Yes. Utility-First uses classes so the property:values does one thing and can be easily combined and reused.
When you define selector on your own, you are mostly going to duplicate the css property:value in it. Which causes CSS size to grow, you have to use modifiers to change the css on certain places like button button--red. This is less likely to happen with utility first.
What you call button button--red I just call <button class="danger">, which will need one selector for the button element and one for the .red class, which will work for any element, not just buttons.
When done right, this gives you a complete n * m elements you can style, with every colour applying to every element type (although, of course, in reality some of them will not be implemented because YAGNI).
My bad, the button--red example was not showing the problem enough.
I am talking about reusing a button in an efficient way. What I mean by that is, when for example a button is used on multiple places and needs various indentation, colors, paddings and alignment.
You can't solve that by just one class. How would you solve that?
The way you phrase that question doesn't even make sense when we're talking about proper rule-based CSS; what's the context for these different indentations, colours, paddings, etc.? Does it depend on the surrounding elements? are certain buttons special? Is there just no clear design idea and every button just gets positioned by hand?
I'm a selftaught (web) developer. On sunny days, you can find me hiking through the Teutoburg Forest, on rainy days coding or with a good fiction novel in hand.
I believe due to the way components are defined. Take a simple Vue SFC. There still is a separation of concerns between script, template and style. + they're meant to be reusable, almost like CSS classes are. So much for the theory.
It gets interesting when you try and reuse spacing, colors or even shadows over several components. The moment Tailwind's promise breaks is when I need the same color for, say a navbar AND a button component. Even worse, you probably have those util classes scattered over your whole codebase.
What if the client changes their mind? I want red instead of purple. You'll refactor the all components that use this coloring. Now you might say 'this can be done with a regex replace-statement'. At this very point, the circle closes if you directly applied Tailwind to the component instead of using dedicated classes.
And I still don't understand how or why it came back
It didn't - this is an extremely common misconception.
That article still only makes it sound like inline styles but a bit more convenient this time.
That still leaves the main problem though: You're inlining your styles in your document. It is inline styles.
No, it isn't, any more than an approach like BEM is. You're still using classes for styling, but the scope of those classes is generally reduced a little. It's definitely not a one-to-one relationship between Tailwind classes and single CSS rules in every case. And, by using the
@apply
directive you can easily extract the styles used to a stylesheet.Fundamentally Tailwind is an abstraction over CSS that provides the following benefits:
It's a particularly good fit for component-based JS libraries like React or Vue where you're actively encouraged to extract common UI sections to their own component. In that context it tends to be extremely quick to style it using Tailwind once you get up to speed, making it extremely useful for prototyping. Further into your project, once you have some styles established, then if you want to reuse them in ways that template partials or separate UI components don't facilitate, then it's easy to use the
@apply
directive to extract common styles and create your own more conventional classes, without losing the advantages of consistency mentioned above.Honestly, I thought the same at first and it took a while for it to click, but I'd never go back. I maintain a big legacy project with a huge pile of messy CSS that I inherited and is very difficult to strip out. That would be virtually impossible for that to happen with Tailwind.
That's not the important part though. Whether you're using classes or inline styles, even if one lets you do more things with less typing, the fundamental difference is that you are inlining the actual styling into your HTML.
There may be a CSS document somewhere that defines some more powerful tools in the form of classes, but those aren't styling "rules" in the same sense as with normal CSS; they end up being more similar to CSS properties, in that they just toggle atomic design elements like a colour or the text alignment.
The actual styling is still in your HTML though, so no, it is just plainly wrong to claim utility classes are somehow fundamentally different than inlining CSS using the
style
attribute. They may be more powerful and convenient, and that might for many be the deciding factor as to why this approach is okay to use while inline CSS is evil; but some sort of defense has to be made. One cannot simply claim that "they're different things" and dismiss all criticism of inlining styles into HTML.There's a separate discussion to be had about whether enough of the problems with inline CSS aren't present, or whether the most relevant ones still remain, and that discussion can be a lot more nuanced and ultimately up to personal preference and picking the right tool for the job.
The
@apply
directive renders much of that moot, though, since once you've settled on a style that works you can easily use that to extract common patterns into reusable classes. It depends on the context you're using it in, and for using component libraries like React it often makes less sense, but certainly if you're using Tailwind in something like Blade or Twig templates then using@apply
is more commonplace.At that point, haven't you just gone full circle and basically achieved nothing other than introducing two new dependencies?
No, because Tailwind still works as an abstraction layer. And you can combine the two approaches however you see fit - it doesn't have to be either everything using the utility classes direct or everything using the apply directive.
It's like JSX in that it sounds arse-backwards when you first hear about it, but if you try it then once you get over the hump it starts to make a lot more sense.
It isn't. But it does feel like it for a lot of classes:
...
Yes. Utility-First uses classes so the property:values does one thing and can be easily combined and reused.
When you define selector on your own, you are mostly going to duplicate the css property:value in it. Which causes CSS size to grow, you have to use modifiers to change the css on certain places like
button button--red
. This is less likely to happen with utility first.More info => dev.to/machy8/comment/1p2jj
What you call
button button--red
I just call<button class="danger">
, which will need one selector for thebutton
element and one for the.red
class, which will work for any element, not just buttons.When done right, this gives you a complete
n * m
elements you can style, with every colour applying to every element type (although, of course, in reality some of them will not be implemented because YAGNI).My bad, the
button--red
example was not showing the problem enough.I am talking about reusing a button in an efficient way. What I mean by that is, when for example a button is used on multiple places and needs various indentation, colors, paddings and alignment.
You can't solve that by just one class. How would you solve that?
The way you phrase that question doesn't even make sense when we're talking about proper rule-based CSS; what's the context for these different indentations, colours, paddings, etc.? Does it depend on the surrounding elements? are certain buttons special? Is there just no clear design idea and every button just gets positioned by hand?
I believe due to the way components are defined. Take a simple Vue SFC. There still is a separation of concerns between
script
,template
andstyle
. + they're meant to be reusable, almost like CSS classes are. So much for the theory.It gets interesting when you try and reuse spacing, colors or even shadows over several components. The moment Tailwind's promise breaks is when I need the same color for, say a navbar AND a button component. Even worse, you probably have those util classes scattered over your whole codebase.
What if the client changes their mind? I want red instead of purple. You'll refactor the all components that use this coloring. Now you might say 'this can be done with a regex replace-statement'. At this very point, the circle closes if you directly applied Tailwind to the component instead of using dedicated classes.
Oh my God, I hadn't even thought of refactoring or redesigns with Tailwind.
That actually caused a legit stress response in me. 😖