Developers September 15, 2020

TailwindCSS, what am I missing?

BrandonClapp

Everyone has been praising TailwindCSS lately. After going through all of the screencasts, I can see that it is helpful, but I honestly don't see how adding 10+ classes to your elements is "easier", or even more maintainable, than just adding css properties to your classes.

For example, in TailwindCSS, you could create a button as:

<button class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded">
  Button
</button>

...which would provide you with a blue rounded button with white text.

However, I don't see how this is easier than writing traditional scss and using a few variables for your colors and padding values.

If I'm already very familiar with the features of sass, what is the benefit of learning the additional abstraction layer? How is this faster for prototyping? I assume that there is something that I'm missing here, what is it?

I'm gonna give it a try, maybe it will grow on me.

  1. 19

    I didn't see the appeal either at first but honestly I think it's made me a better designer. Here are some reasons why I like it that haven't been mentioned yet.

    Firstly it's really hard to break stuff. At my old job we had a mammoth code base and tonnes of shared classes everywhere. The problem was that any CSS change often broke other screens. Even a simple padding fix would change things in random places and you wouldn't know for weeks. Maintaining CSS at scale is hard.

    With Tailwind everything is confined to the element (mostly) and I'm not scared of breaking stuff anymore. An added bonus is that you can copy/paste HTML and the styles come for free. So building new components off of existing ones is extremely quick.

    Secondly the real power is in the media queries. Almost every component I build has a row and column layout to deal with varying screen sizes. Add in some hover/focus states and you would have 4 separate CSS definitions to make. Where do you put them? Do you keep them together or group base/state/media styles in different parts of the file? Either way it gets messy as the styles grow.

    With Tailwind that's just one line: flex flex-col md:flex-row hover:shadow focus:shadow-outline. Responsive styling has never been easier I reckon.

    Some others:

    • All styles are neutral by default (via normalise.css) so you always start with a clean slate
    • Default styles play together well so everything just looks nicer (especially colours)
    • The config file is your centralised design system, is extensible, and has cool plugins
    • No need to think of class names and no class name collisions
    • Things like gradients are built in and work with your colours. Much easier to use in than CSS.
    • Total CSS size in prod asymptotes because classes are reused

    Honestly I have nothing but good things to say and you should definitely try it. Also use the VS Code extension to help manage the styles.

    If anyone wants tips, help, or has questions you're free to hit me up 👍

    1. 2

      Excellent points. I've been playing around with it today and think it's growing on me. My example of just the button was too trivial to see the power or take those things into consideration.

      1. 1

        Nice, glad you're liking it! It's not perfect (nothing is) but it's made my dev life easier and I'm always keen to spread the word.

  2. 15

    Unlike many devs I actually enjoy writing css (usually scss), and have never tried a css framework that I liked. In my opinion utility-based libraries like Tailwind end up producing cluttered looking html and start to erode the benefits of keeping structure and style separate. I'm also a designer, and I dislike the rigidity of these frameworks. I'll decide exactly how things look thanks kindly!

    That being said, I understand why a lot of people hate writing css, and using a framework means that your styles will at least be consistent, which is a good thing. There are also definitely other areas where I use tools like this. For instance, I don't really like managing servers, so I lean heavily on platforms and technologies that minimize how much time I spend doing that. There are plenty of coders who are happy to deal with those tasks, and would prefer to setup their server environment exactly how they want.

    We can't all be super-ninjas that do everything, and I think most people have some areas they prefer to leave to others.

    1. 4

      Yea I think that's kind of how it's marketed, but when I was digging into it it seemed like you still had to be super familiar with CSS to use the framework. Most of the classes that you add to elements are 1-to-1 mappings to a css property.

      If I want to use flex and center items, you still have to specify classes like flex, align-items, justify-content, ...etc except those get cluttered in the main markup instead of the CSS file. To me, it still feels like you're writing CSS, but it becomes a "where do you want your mess" topic.

      The more I dug into it, i just didn't understand the appeal, so I was assuming that there was something that I didn't understand.

    2. 1

      One of the reasons people like Tailwind so much is that it is not very rigid. It's just a set of utility classes that you can use, and you can use them to make your own utility classes as well. In that sense it's more like a CSS library.

  3. 4

    To buy into tailwind, you have to first buy into functional/atomic/utility-based css, which is frankly the opposite of traditional css. Traditional css is about separation of concerns and re-using classes. Functional css is about being combining your html and css together making it more "declarative".

    So in your Tailwind button example, you can see right away that it's a button element and you can see the styling right there. You don't have to look up a .blue-button class in some stylesheet somewhere and then come back to html to see how it fits together.

    For small projects and solo developers, there honestly may not be much productivity gain compared to scss/sass, and you may actually be worse off. But as your project gets bigger and your team gets larger, constantly trying to figure out what someone else's styles do, and why you're having cascading error/conflicts can get messy. A framework creates productivity gains not only with standardized utility classes but also pre-built components.

    I personally like Bootstrap (Bulma is good too) which are both a nice mix of pre-built components/styles plus the ability to customize with both scss pre-processing and utility classes. I style my own css only as last resort, if I can't get either the components or utility classes to do what I want. As a result, my stylesheet is only about 50 lines. But some people really want fine-grained control over their styles and end up "fighting" these pre-built frameworks, so Tailwind was born where everything is a utility class and there are no component-classes that get in the way.

    Bootstrap has worked very well for me so far, and only once or twice have I had to spend time "fighting it" to get what I want. But I could easily see that at some point if I want to start changing everything, then I'm going to be fighting it a lot, and then that's when I would consider switching to Tailwind to re-build everything up from utility classes.

    That's my interpretation of how Tailwind took off.

    1. 2

      For small projects and solo developers, there honestly may not be much productivity gain compared to scss/sass, and you may actually be worse off.

      For me it's been the opposite. My productivity on small projects has skyrocketed since adopting functional CSS and utility classes. I was skeptical at first, but once I fully embraced the mindset it's saved me sooo much time. I don't use Tailwind, but just build a few small utility classes as I go.

      For example, with the following three classes that I use in nearly every project, I can almost completely forget about dealing with padding and margins:

      * {
        padding: 0;
        margin: 0;
      }
      
      /* I also create .pad-2 etc for multiples of the grid size of 8px */
      .pad-1 {
        padding: 8px;
      }
      
      .vertical-stack-1 > :not(:last-child) {
        margin-bottom: 8px;
      }
      
      .horizontal-stack-1 { display: flex; }
      .horizontal-stack-1 > :not(:last-child) {
        margin-right: 8px;
      }
      

      Then, if I want a padded box with items spaced vertically, and spaced buttons horizontally:

      <div class="pad-1 vertical-stack-1">
        <h1>Shopping Cart</h1>
        <div class="horizontal-stack-1">
          <button>Edit</button>
          <button>Pay</button>
        </div>
      </div>
      

      I also love the simplicity. It's just plain old CSS - no need to set up CSS transpilers or bundlers, just copy the handwritten .css file across and you're good to go.

      1. 1

        Same. Productivity is increased.

        The other benefit that I have is a much easier thinking about the document in terms of design using Tailwind rather than a more traditional CSS approach. Tailwind actually unlocked more creativity in me, to an extent.

    2. 2

      Yea, I suppose it does take a more compositional approach. I get the point about having to go look at the CSS to see what's going on.

      I kind of got away from Bootstrap once I did a deep dive into CSS grid and flexbox and have been doing custom ever since, and it definitely is slower, but I think bootstrap was a really great example of a fast prototyping system because it had the pre-designed components that you need. However, after looking into Tailwind, it seems like TW competes more with actual CSS/Sass than it does BS.

      IMO, it seems like that inherently ties your markup to a single design. For example, if you wanted to support multiple themes or have a dark mode, all of your .bg-blue declarations kind of negate all of that.

      I suppose that's the tradeoff though. Design your application in the same markup file but lose separation of concerns.

    3. 1

      very good on solo work vs working in big teams

  4. 3

    Like any other framework whether it is for applications or css or anything, the whole point of the framework is to abstract something away and do some of the "heavy lifting" for you.

    IMO, in general, I thing large frameworks are bad. I blogged about my thoughts on why that is over 2 years ago:- https://www.paulcourt.co.uk/article/ditch-the-framework.

    They can be very good for prototyping and deliver results quickly. However I believe they are born out of a lack of understanding ether directly by the person(s) creating the framework or for the target audience of the framework. i.e. a multi-skilled team where you have different levels of developers with different primary disciplines - you need to find common ground and lower the barrier to entry.

    For HTML+CSS specifically, you also have to consider how the HTML is being generated. CSS was born at a time where it was normal for entire HTML documents to be statically written and then you wanted common styling across an entire site. Anyone preaching CSS best practice would tell you that your class names should identify WHAT an item is and not HOW it should look. For example <button class="call-to-action"> or <button class="cancel"> so that you could then have 1 css rule to define how all your call to action buttons would look.

    If you already have a complex templating system for your visual components, then the abstractions that CSS provides might already be made redundant, since changing a single template file will already change how that component is rendered across your entire application anyway (Eg. like Vue.js or a well structured twig setup).

    At the end of the day, if it's just you writing the code, you can do whatever feels best for you.

  5. 3

    Hi! I've been using TailwindCSS for quite a while now and I also wasn't very convinced about it in the beginning, then I started to like it and now I use it everywhere.

    I don't like writing CSS much to be honest and now that I am used to Tailwind and remember most classes I find it a lot easier to create responsive designs that look consistent and exactly like I want, very quickly, with Tailwind.

    The only two issues with Tailwind for me are 1) it's also easy to end up with a lot of duplication, but that can be easily avoided using @apply. I use it with any combination of more than 3-4 rules that I need in multiple places for the same kind of thing (such as buttons and things like that), so I just use a custom class applying Tailwind classes instead of repeating the same Tailwind classes everywhere.

    1. If you don't use the now built in purge-css feature the bundle can become quite large, and in most projects there can be a lot of unused Tailwind classes.

    Other than these two issues, I really like it. It's easier for me to compose styles with Tailwind classes that build my custom CSS classes each time.

    1. 1

      I've been giving it a try today and I think it's growing on me. It does seem a lot faster.

  6. 3

    Give this a read which may give you more context on utility based css https://adamwathan.me/css-utility-classes-and-separation-of-concerns/

    1. 1

      Perfect, thanks for sharing. I'm sure this will clear some stuff up.

  7. 3

    Tailwind is a nice tool. I don’t use it for everything, but I see a couple major benefits to a utility first approach:

    In growing projects with multiple developers, it’s important to maintain consistency. This can be done by carefully safeguarding a set of conventions and SCSS variables and using them rigorously, but frequently you’ll find border radius defined slightly differently in different places or colors just a bit off. Using utility classes goes a long way to consistency.

    On a number of projects, CSS becomes a tangled mess. Every developer writes the CSS they need at the time of implementation; there’s lots of styles left that don’t apply to anything (but it’s Nearly impossible to see which ones). Lots of duplicate declarations under different classes with possibly subtle differences, inconsistent application of media queries. Tailwind is a different paradigm, where you don’t have hardly any CSS to write or maintain, and gives you a structure to express styles.

    There’s a subtle weight to decisions like “which blue to use?” Or “how much space here?” Or “what’s the standard border radius?” that a utility-first approach helps ease by providing a defined set of classes. The flip-side is that this is more rigid, and some may not prefer this.

    Finally, there’s immense power in being able to make global changes by changing the tailwind config. You can completely and consistently change the entire appearance of an app by tweaking the config (like if you want a darker shade of blue everywhere, that’s a one-liner).

    I don’t use Tailwind for everything, but I’ve found it useful.

    1. 1

      You brought up some great points. One thing I hadn't thought about is easily seeing all of the references for a given class.

      I've been thinking about supporting different themes, though. The way I've done that recently is with CSS variables and it seems like directly tying your markup to the styling creates tight coupling between those two things.

      Do you know if TW supports something like this?

      1. 3

        @BrandonClapp, the way I'd solve for this is to use some theme classes applied to the body and then use cross-theme classes for things like colors, rather than Tailwinds built in colors (and other properties, like font-sizes, if your theme changes those out too).

        Here's some sample code if it helps...

        // scss
        .theme-1 {
          & .text-primary {
            @ apply text-orange-400;
          }
         /* snip ... same for backgrounds, borders, or other theme-able colors or other */
        }
        .theme-2 {
          & .text-primary {
            @ apply text-blue-400;
          }
        }
        

        In your components, you do:

        <h1 class="text-primary">I'm a theme-able primary color</h1>
        

        And, to change theme, you change the body class from .theme-1 to .theme-2.

        There might be another way in Tailwind to do theming too, but that would probably be my approach. :)

        1. 1

          That's a good solution. I did a bit of research last night on tailwind theming and I think they may already have something built in for this. Maybe theming isn't as big of a deal as I was thinking, but I believe the key will be to stay away from built in color classes.

          1. 1

            It looks like Tailwind supports changing out its default theme in custom ways (like globally change border radius or colors to something that isn’t the Tailwind default), but it doesn’t seem to have multiple themes built-in, unless maybe you compiled a couple of style sheets using different configs and hot swapped them

      2. 2

        @BrandonClapp, about separation of concerns and coupling, I think this article from Adam Wathan (before Tailwind came out), helps explain some of that: https://adamwathan.me/css-utility-classes-and-separation-of-concerns/.

        What's your key concern there? Has that coupling in the past made projects hard to change or brittle in some way?

  8. 3

    If you are "compiling" the css code, you can use @apply for classes.

    https://tailwindcss.com/docs/functions-and-directives#apply

    I'm not a front-end dev, so these might be nonsense. I'd say it's an alternative to bootstrap like frameworks instead of sass and I'd say it's doing a better job on prototyping if you have a beginner to mid level knowledge on html & css. It's quite easy to setup a layout. Ofc it could be done with flexbox or grids. But it's a matter of choice.

  9. 2

    I've had several friends who I trust very much try to convince me that Tailwind is the future, but it just doesn't work for me... for the reasons you mention above, and more.

    The indefensibly long class soup markup makes my eyes burn. I think it's a kind of disrespect, a passive condescention towards people who actually want to read your markup. Never mind the fact that it drastically increases the likelihood of typos and makes future refactoring a brutal slog of find-and-replace.

    However, the two bigger issues are discussed less frequently.

    First, there is this notion in Tailwind that I have this perfect design in my head which needs to get out, and that the purity of the implementation of this design is going to be adulterated by me forcing a square peg through the round holes that say, Bootstrap provides. The opposite is true; I have a solid 3.8/5 technical understanding of 95%+ of the CSS properties, hard-won wisdom gained working on web projects since the bad old days... but I couldn't build a compelling site or CSS framework from scratch if my life depended on it. Why would I be able to? I want to use Rails, not create Ruby. I can barely keep all of the classes for flexgrid or responsive breakpoints in my head... why would I want to burn the time required to build them from scratch? I don't want to have to invent a button, a card, a tab. Just give me the usual suspects and let me build apps that deliver value quickly.

    Second, the elephant in the room is that Bootstrap has a enormous library of themes available. Some are great and many are terrible. Some are free and many are paid. (Tip: you get what you pay for.) The first step towards me building anything is to find a theme that generally expresses the vibe I want to go for, and then breaking it down into bits that I'll use to actually make the thing. So far as I can tell, the only thing Tailwind offers is a $250 UI kit that offers what Bootstrap gives you for free, but with none of the context example pages. I would argue that when you buy a travel booking theme or a SaaS theme, 75% of the value comes in the form of the example pages. Again, it's the difference between handing someone a paintbrush and a blank canvas vs. giving someone a box of collage-ready cut-outs. Sure, maybe someone who wants to create the next Rome is out of luck, but the 99% of us who just want to do a good job on a project and go home need these sorts of building blocks. It's wishful thinking to imagine that we're all going to wake up tomorrow with strong opinions about design that make the need for good starting points irrelevant.

    Just my $0.02.

    1. 1

      Yea I was kind of put off that Tailwind UI cost as much as it does - not saying that the amount of time that the creators put in doesn't justify that price, but it's a hard sell when other frameworks exist that give it to you for free.

      I feel like there is a good opportunity for something like tailwindcomponents to grow. One of the most helpful things with Bootstrap is the plug and play model. It may not be the nicest looking thing, but it does help with rapid prototyping. A library of pre-made components that can be easily tweaked would be great.

  10. 2

    My issue isn't that I don't understand why it's useful, it has benefits over previous methods obviously, but I don't understand why you wouldn't just use inline-styles in a dynamic way given that the "use case" is for components and given we now have templating options that easily allow for dynamic styles (and classes for that matter) to be inserted into templates.

    In other words, you want to write a card component. You're going to use a template I'd imagine and then that template is going to provide a means of altering styles. Where is the need to use classnames? It just doesn't help. You're just adding "middle management" and like all middle managers...they're inefficient.

    So I want some padding around my card. I can either indicate padding using a classname with a prefix...or I can just reference the style I wish to apply directly and pass in the value.

    In VueJS this might look like:
    :style="{padding: paddingValue}"
    ...but what's more, you can do:

    :style="styles"
    ...where styles is an array of styles and associated values passed in dynamically (You could also do exactly the same thing server-side with a scripting language of your choosing).

    Is that not the optimal solution here? Rather than assigning classes that directly represent individual styles? Perhaps I'm missing something!?

    1. 2

      To extend on Matt's point, when you're applying classes for every css property in your markup, along with event handlers, loops, and other templating logic via React/Vue/Angular, it seems like your throwing all of your concerns into the same file.

      Doesn't this make it hard to see the actual logic of how the interactions happen when you have all of your classes on the same elements?

      For example, do you put all of your event handler logic inline like

      <div onClick={ (e) => {
          // ... some 30 line function
      }}>Click me</div>
      

      or do you create another function at the top of your component to handle that? I guess I see adding all of your classes inline like this as cluttering everything up in a similar way.

    2. 2

      One thing you can't do via inline styles are media and state (hover/focus) queries. So for those you MUST use CSS. In Tailwind you just change the prefix.

      If you're extending existing components then a big problem with media/state queries is that you have to override styles with even more specific CSS selectors.

      So if someone writes media (...) { .container > .component:hover {} } you basically have to duplicate that definition with your extra style to allow it to be applied in that specific case. You could use !important but then you're restricting that new style even more.

      And if you make a change to the base component in future? Then you have to be very careful to not break extended styles or styles on other screens like that. CSS is just messy once you get to that point I reckon.

      Also there's a lot of be said about the restrictive nature of Tailwind CSS when it comes to design. Styles fit nicer because they're restricted to sensible defaults. You can always extend the defaults but the base styles look nice and help your components to look consistent throughout your product.

      1. 1

        Of course you can't, but still, surely you'd just create those media queries for a given component? I can't think of many/ any instances where I'd be re-using media queries across multiple components! Can you?

        1. 1

          Perhaps less so much with media queries but hover/focus styles all the time. But my point that that extending components with CSS is rought with having to override existing styles. This adds complexity and potentially breaks stuff.

          Seeing .component:not(.component-alt) > .button patterns is common place on larger code bases.

          I suggest you just try it out. I had similar concerns but the more I've used it the easier my dev life has become.

  11. 2

    Especially when using Vue where css can be scoped to the component, I don't really see the point either.

  12. 2

    For me is easier than CSS and more complex than Bootstrap.So it was a great change for me . Maybe is not so good for CSS experts

  13. 1

    you'll only get it once you start using it

  14. 1

    When you work on a big project and you have a lot of css crap it becomes very cluttered and hard to navigate. It's just more naming conventions IMO.

    Tailwindcss works very well with SPAs like react.

    Also it's very easy to copy a component from another website. Just open the console and copy & paste. It is also very easy to use components from a tailwindcss theme. I literally copied the website of tailwindui in 15 minutes and added my styles to play with. Try to do it with custom css in that amount of time.

    Also when you buy themes like those that are made on bootstrap, you need to learn it. You can't just use it.
    With tailwindcss no need to learn the fracking theme every time, its conventions, dealing with its bugs. No need to overwrite existing frameworks like Bootstrap that definitely don't solve the problem unless you want your website to look like from the 80's.

    Custom design is nice, but I don't have the luxury to spend hours on designing everything with css, put it in folders, organise everything, respect patterns...etc. And it won't be very reusable anyway because the next project will have a different design or different conventions.

    It is also very easy to change the colors and themes, not like with styled components.

    So in a nutshell, productivity productivity productivity !

    1. 1

      These are all extremely convincing points. Thanks.

  15. 1

    I'm not a full dev, but I'm agree with you, I don't see any added value. Bootstrap is perfect in that job of css framework, or pure css is great also...

    1. 1

      IME, Bootstrap is quite complicated to customize. One of Tailwind's strengths is customization is pretty straight forward. But if one already has bootstrap setup and working there isn't much benefit in switching.

  16. 1

    Hi! I have been using tailwindcss for a couple of months now. I was familiar with bootstrap and scss prior to that and, of course, plain css. I've been working with html and css for about 8 years now. What I think as a great advantage of tailwind is exactly what you consider a "meh" feature. you can just write "flex justify-center items-center" in the same html document your are using, whereas in plain css you would need to name a class, then go to the css file, and write .class-name{ display: flex; justify-content: center; align-items: center;} (about 30 characters and not changing files vs about 3 times the characters and file changing). I also do think that you need to be not an expert but at least advanced in css in order to use tailwind. And also somebody talked about the "rigidity of these frameworks". Tailwind is the exact opposite. You create the button however you want it to look like. It doesn't carry any predefined styles like in bootstrap. And you can also configure the base tailwind.config file to suit anything you need. (colors, spacing, font, everything). I just find it waaaay faster than writing css in a style.css. But that's my point of view. Hope it works for you.

    1. 2

      Yea I suppose if you're always just working in a single file it would be quicker. I usually have a split window with my HTML on one side and then the SCSS on the side, plus a VS Code plugin for scaffolding classes.

      <div class="flex justify-center items-center">Some content</div>
      

      vs.

      <div class="my-content">Some content</div>
      
      .my-content {
          display: flex;
          justify-content: center;
          align-items: center;
      }
      

      I suppose it saves a little bit of typing, but it reminds me a lot of using inline styles.

      1. 2

        The difference comes when you have that same content repeated 15 times in an application. Maybe it's a call-to-action type of thing. Then you decide it actually looks better left justified.

        depending on how your HTML generation is structured, you might find yourself doing a lot of find-replace or copy-paste.

        1. 1

          I never used TailwindCSS (I usually write my own utility classes when I need them, but I mostly work alone).

          I think why refactoring isn't that big of a deal in Tailwind is because it's usually used with other frontend framework such as React or Vue. If you have a CTA button you would actually use a single CTA React component that is re-used in your entire project. So if you want it to be left-aligned, you would just change the classes inside that component.

  17. 0

    A lot of devs have Shiny Object Syndrome.

    1. 4

      I use to think the same way until I saw the benefits others mentioned here. Responsive layout is very well handled in Tailwind also the reason I don't need to switch between html and css files itself is a pleasure.

Recommended Posts