This is precisely where Tailwind breaks down IMO. It's fast for landing pages and smaller sites--but when implementing a real design system across a complex web app, Tailwind is a nightmare. We've had to add so much custom stuff to the config file it's basically the same mess our CSS was before.
I've been-there-done-that with the whole CSS framework world (have used Bootstrap, Tachyons, Bulma, Tailwind in many projects) and have completely reverted back to custom stylesheets with a few select utility classes that make sense.
Padding, margins, widths, heights do not make sense as utility classes IMO.
Type scales, type modifiers (like font-weight), and commonly used things like margin-x-auto and 100% width do.
I wish there was a CSS framework that only contained a minimal set of common utilities (like the ones mentioned above) and required no complex build process BS or NPM.
I just want a simple boilerplate, nothing else.
What you need to do is heavily use the `extends` property of your tailwind.config.js so it applies the paddings and margins you seek to ALL properties.
I'm curious what you're adding to your custom config to make it so bloated? I've been using Tailwind on a number of sites, big and small, and have yet to run into any situations like you've described.
The custom stuff in our config was mostly the need to create standard styles for components. Eg. button large, button small, etc. to correspond with our design system.
For example, here's tailwind code required to create a button large: bg-violet-100 text-violet-700 text-base font-semibold px-6 py-2 rounded-lg
How the hell does that help with consistency? You have to copy paste that mess every time you create a new button, and then guess what happens if the button you copied from needed special margin? Try debugging that if something looks wrong. Also try turning that into dark mode.
Now you've got to search through the spaghetti to find what's custom about this button and fix it every time.
You know what's easier? Creating a ".btn-lg" style to fit our design system, and just typing .btn-lg each time. It also has the bonus of making your code actually readable.
Maybe this is solved with the groups functionality in the latest tailwind, but this is just one of the frustrations I eventually developed.
No, your designers should already be working to scales for size, colour etc. which you can implement in Tailwind. If they don't, now's a good time to start.
> How the hell does that help with consistency? You have to copy paste that mess every time you create a new button
You're extremely not supposed to copy-paste that. You're supposed to extract it somehow, either with your Javascript component framework, or by making a semantic class with the @apply directive.
https://tailwindcss.com/docs/extracting-components
The difference is that Tailwind allows you do some quick work without coming up with abstractions. So you work bottom up instead of top down.
> then guess what happens if the button you copied from needed special margin?
That's the beauty of it! You have a button class, and then if your button needs "a little extra" you add the button class and the margin utility.
At my previous job, when this situation came up, the normal way was to make a BEM class specific to the location, import the button in that (with a SCSS mix-in) and add the margin. So the HTML would have a class name that was specific to this one button, but you didn't know what it added: class="info-page__navigation__button". With Tailwind, you get 'class="btn mx-2"' and you can basically see what it's going to look like.
If I’m using React components, tailwind makes even less sense.
I’ve already separated my button large out as a component, guess what happens in a mature design system? The system gets updated and changed to fit the needs of the product.
So what happens when you need to change button large in tailwind? You need to restyle the button with the spaghetti mess (maybe add something to the config), then re-extract the mess into a tailwind component. Now you’ve got components within components just to emulate the abilities CSS has right out of the box.
Guess what you could have done? Just had a .btn-lg class in an old school style sheet where you updated to the new font weight and padding and you’re done!
There is no need for this layer of complexity and abstraction of CSS. CSS is literally the easiest thing in the entire stack. Why do you want to make it so complicated?
Rube Goldberg machines are extremely elegant in their beauty, but they are not the most efficient way to get something done.
I absolutely do have a .btn class in my Tailwind projects, that's a given. For consistency, it's built from the utility classes that Tailwind provides, but buttons are kind of a pathological case in many ways, they're really not how you should evaluate a framework. When I put two buttons next to each other, I don't make a new class for one of the to get some spacing, I just slap a "ml-4" on one of them, and that matches all my other spacings.
But the real magic is when I'm building up my mid-level components, I don't have to try to come up with names or abstractions for the CSS, I just make things look and work right, and as I notice patterns I can break them out into semantic classes as needed. It's a great way to work and the results have been good for me.
In my mind, the real mess is a bunch of poorly named CSS classes that end up being specific to the place where they're used. Specificity battles, 40 character BEM selectors, mismatched margins sizes and randomized colour palettes. Setting up a Tailwind configuration is a very ergonomic way of turning your basic design system into CSS.
In other wards instead of doing <button class=“btn-lg><button/> you're doing <Button {...specs}/>.
This is also what CSS does for you natively. Tailwind is a beautiful, elegant, and ultimately unnecessary layer of complication.
It feels powerful and fast to beginners, and then you go through a design system overhaul with it, and start wishing you had just used bootstrap style class names and avoided the whole mess.
When it comes to code reuse, either extract the button to a component that you reuse, or extract it to a class in tailwind.
.btn { @apply px-4 py-2 rounded }
Now you can just add the btn class and you’re done. If you ever want to change that button you can just update it and be done. If you want a button with different padding add btn px-8 and you’re done.If you’re using components then you just create the button in a single place and reuse it. If you have custom requirements for the button then you override it.
It’s really quite simple and easy to do everything you’re describing. I’d read the docs and watch some videos on it and start working with it instead of against it.
Or don’t use it at all, makes no difference to me!
.btn { padding: 4rem 2rem; border-radius: 2rem; }
rather than .btn { @apply px-4 py-2 rounded }
It simply feels like an additional, unnecessary layer and, frankly, somewhat wrong.Agree with that. Wish the custom theme mechanism becomes mature enough like React components.
Until then the best bet i found was to use our own styles along with tailwind class names
Otherwise you’re just fighting against the framework.
Why not? They usually benefit from having consistency in the design and that's where utility classes work best.
However, tachyons is even worse than Tailwind in that it offers far too few classes for margins, padding, widths, etc. so you end up having to build everything custom anyways.
And you can't just "try" one of these frameworks once or twice, you have to memorize their particular syntax or you lose all of the benefits of using them. After spending hours learning tachyons syntax and googling about 17,000 times, I had forgotten the tailwind way. And when I went back to tailwind I had to google every time I wanted to add a style again.
Ultimately, CSS frameworks don't save you time unless you pick 1, customize it to your needs, and do front-end stuff full-time so you don't forget the syntax.
We use what they give us, it works.
As in
color: c(cool-gray-800); background-color: c(cool-gray-100); font-family: ff(sans-serif); padding: s(m);
Where c, s and ff are SCSS functions returning a value defined in scss maps.
If you find the tailwind definitions useful, they’re easy to borrow.
I would completely get behind tailwind if it was only the SASS part. Give me a bunch of mixins and consistent variable naming, which I could just `@import` into a sass file where I get the definitions for UI elements, widgets, etc... the whole "Design system" if that is the word kids use these days.
All of that can (and should if you actually paid attention at the CSS Zen Garden) stay outside of the HTML. So why when I go to any introduction to Tailwind it still shows all that <div class="size-foo color-blah rounded-baz"> code, I get major WTFs on my head and then I just go back to my simple SASS-based workflow.
What I'd like to see in the next generation of CSS frameworks would be for it to be able to take a completely classless HTML document (like CSS Zen Garden, modernized to HTML5?) and have it look like 3 or 4 different design systems without touching the HTML. Or for extra points, take a web application like webapp (web version of winamp) and show how you can make completely different skins just be redefining the base types and the color palette.
Not entirely true. I'd be totally fine with class names that identify what type of widget it is. <div class="card">, <div class="modal"> <button class="secondary-action">, or <span class="clipboard-copy"> are "made up CSS class names" that identify a type of widget and used without making no assumption about presentation concern. <button class="btn btn-small"> and <div class="w-12 rounded-small"> are not.
And yes, I understand that tailwind allows you to create types and @apply them. What I am saying is that (1) I'd like to see this separation to be enforced and not just possible and (2) plain SASS also lets you do that already. so I don't understand what I would gain from adding tailwind.
> Components are a better way for separating concerns
Except when they aren't. Downthread I gave the example of a library project that I want to define the functionality/behavior but leave the looks/styling to the consumer.
Desktop GUIs have theme engines for ages, yet frontend web developers want to get excited about frameworks that allow for "night mode"? "Night mode" is just a way to say "you can separate presentation and content however you want, as long you only present in two different styles".
You can only change so much of the styling without changing markup.
https://tailwindcss.com/docs/theme [1]
> You can only change so much of the styling without changing markup.
I take that you are not old enough to remember the CSS Zen Garden?
Even with craptastic CSS2 implementations of IE7 and no browsers that could fully pass the ACID3 test, the Zen Garden showed how anything could be changed without touching markup.
Don't tell me that it's harder in 2020 because it is a whole lot easier.
Tailwind does “enforce” separation of concern between styling and content, just in a different way than the separation of html and css.
Consider the utility class m-1 and m-2. What they are supposed to say is that element with m-1 class and element with m-2 class should have different margin, with the m-2 element probably have a slightly bigger one, and every element that uses m-2 class should have the same margin. It doesn’t specify styling at all. The concerns of styling are completely separated into the theming system.
All that the utility class define is the relation between elements. Eg. which elements should have the same margin/color/typography etc... This would also provides consistency in your designs, unlike pure css which allows you to do whatever you want without defining structure and relationships between elements.
I would say tailwind forces you to separate styling concerns out of your content and into your theme. You could probably replicate css zen garden using tailwind theming system.
But if you are saying that you have different "utility" classes to specify different margins, and if these classes end up in your HTML, you already have styling/presentation definitions that should never be the concern of the document writer.
I was there for the Zen Garden, and it was great at the time and in its context (Flash and image maps!), but now I'm using the web stack for a 3D editing application, and my last job was complex GUI for managing large number of IoT devices. The idea of separating "the content" from "the presentation" does not apply anymore. It's just not a thing. Good software engineering is super important, more-so than ever I'd say, but keeping some parts of the UI in the .css files and some of it in the .ts files does not equal adequate "separation of concerns" in my context. It's just not that simple anymore, and in fact in the previous job it was an impediment, since UI refactors became much harder because of the state of the .css files. In my new project, which was moved over from Bootstrap shortly after I started, Tailwind has made sure that many of the old problems just don't arise anymore.
This smells of complexity to-justify-my-paycheck thinking about software. Css and html go well as seperate documents which makes things like theming and maintenance work but not frustrating. Why do we need the tooling overhead if the gains are marginal? SCSS gave css the powers it needed to be flexible but Tailwind sounds like classic cool-kiddery just like react.
The fact that most front-end frameworks implement some kind of React-ish approach should at the very least make you wonder if dismissing it as 'cool-kiddery' is perhaps a bit too broad a swipe.
With Tailwind, at first I had similar concerns. I used it a bit and it seemed okay, but went back to the good old fashioned way of doing things. Then, in a later project, I decided to give it a proper shot and it measurably increases my productivity, reduces complexity, and reading articles about why it's not 'separation of concerns' (in many cases) convinced me I had no real basis for being against it other than being a curmudgeonly old-skool guy.
It's totally fair to stick with what works for you, but perhaps dismissing both React and Tailwind as 'cool-kiddery' is more a 'stuck in your ways and insecure enough to need to justify it' kind of thing than it is a reasonable perspective. Sometimes new things /are/ better!
React etc. are extremely nice if you're making complex applications for the web. Of course it can be overused, but I'd say that some kind of SPA framework (and state management framework) is a requirement for the work that I do.
Yes, with vue it is nice to have <template>, <script> and <style> on the same file, but what if I'd like to have multiple styles? Why can't I say "This component has this structure and this behavior and it allows for style A, B, and C" and have the application bundler choose themselves what style they want to use? What if the application bundler thinks "I want to use style C, but I'd like to customize some rules"? How do you do that?
> moved over from Bootstrap shortly after I started, Tailwind has made sure that many of the old problems just don't arise anymore.
Yes, Tailwind is a step up compared to Bootstrap if you consider how you can define the types and remove the utility classes from your HTML. But my feeling is that people who are so fascinated by the idea of Tailwind custom types are just in the process of reinventing semantic styling, this time with a preprocessor to compensate for the verbosity and some helpful mixins to overcome inconsistencies between browser implementations.
So, to repeat the question: What am missing? What do I have to gain from Tailwind if I am using already SASS as the preprocessor and a good library of "utility classes" that can be @imported/@use'd/@apply'd to the document without touching the HTML?
Right, and I don't see the HTML and the CSS as separate concerns when the HTML describes a GUI, not a document. There being two languages in play is a historical detail that as developers we have to tackle in the best way. I don't believe that it's some sort of holy spirit we have to respect.
For my money, separation of concerns is things like where do I put my mutable state, which part of the application talks to the network, etc.
> but what if I'd like to have multiple styles
I have to say that's not a thing I've ever needed to worry about. I'm worried about things turning into a big pile of goop. The old approach too often devolved into making a separate class for each tag. Starting with repetition and noticing patterns that then get factored out is a better approach for me.
I will say, though, that in Tailwind it absolutely would be workable to give e.g. colours a semantic name - like primary and secondary - and then map those to whatever you want, including CSS custom properties. So you absolutely can implement both build-time and runtime theming at that level if you want, where you just need to change configuration options or a set of properties.
> What do I have to gain from Tailwind if I am using already SASS as the preprocessor and a good library of "utility classes" that can be @imported/@use'd/@apply'd to the document without touching the HTML?
Again, I'm not afraid of touching the HTML, that's not a goal for me. In my work, any change of any consequence is going to involve both HTML, CSS, and JS anyway. I am much more afraid of accumulating cruft in poorly-maintained CSS files.
Tailwind's utility classes are pretty fantastic - for instance, you can define a colour palette and they also become usable in gradients - so they're a good place to start. I also like that it's basically real CSS because that forces developers to learn, which will lead to better layouts. And yes, it will in some cases lead to the same set of classes as a semantic approach, because sometimes that classes are what makes sense. But the thing is, how do you arrive at that set of classes, and what do you do with the edges and boundaries and all the glue you need. Tailwind provides an extremely usable starting point and a good thought pattern for building the type of apps I do.
You know that you can create themes in GTK (a Desktop GUI) using CSS nowadays, right? Whether a document or a GUI, behavior (how it works) and presentation (how it looks) are still separate concerns.
> (Multiple styles)'s not a thing I've ever needed to worry about.
Yeah, others have though - both as consumers and as integrators. If you are okay with the idea of re-inventing wheels every time you want to have a different color, plenty of people are not.
> I'm not afraid of touching the HTML
It's not a matter of being afraid to touch HTML. It's a matter of not being able to! Whether in terms of ability (some marketing person that is putting together a wordpress or Shopify store and can only go with different artifacts provided to them) or from the nature of the source code (e.g, imagine you want to make a RSS/Atom feed reader, embed a Tweet on your site with a custom styling or use an OSM tile editor), if you are not able to touch the code but you can select different styles, then it is fundamental that the data is separated from the style definition.
You might not think that this is important for you to do your job, but I think that is extremely short-sighted. What made the web as interesting as an application platform was the idea that the user agent could be extended. It is in our interests as users to keep the web open and able to be tinkered with, and the easier it is to separate the layers that people want to improve, the better.
Does GTK offer CSS layouts? Do I describe the elements of the UI using HTML? As far as I know they just use a subset of CSS - aren't the selectors predefined by the framework? I don't recall, exactly. But GTK provides an entirely different set of primitives, I don't think it's the same problem at all if you're just providing fonts and colours. Again, I'm talking about something rather specific, creating complex, desktop-like user interfaces using HTML and SPA frameworks.
> behavior (how it works) and presentation (how it looks) are still separate concerns.
Yeah, but I wouldn't say that that distinction maps to the distinction between CSS and HTML at all, not in my context. HTML, especially document structure, is also presentational. That's really what I mean when I say it's not a "document".
And any way, no matter which approach (and platform, I'd wager) you use, if you want to completely restyle a complex GUI application like what I'm writing in the way you could restyle HTML documents like the Zen garden, you're looking at some serious engineering effort in keeping the so-called behavioural HTML and Javascript in check and documented. It won't just be about how you handle the CSS, it'll be about how you handle everything.
> Yeah, others have though - both as consumers and as integrators. If you are okay with the idea of re-inventing wheels every time you want to have a different color, plenty of people are not.
I actually feel like I have better control of my colours with Tailwind than I ever did. Currently I'm using a limited selection specified in the Tailwind theme. They have names like $adjective-$colour, so it'd be weird to change them, but if that's important to you that things are themable, as I stated, you can put in the effort to set it up with semantic names and make them customizable at build time or at run time. I still think you'd have a better experience than making separate classes for every tag and reimplementing that for each theme.
> It's not a matter of being afraid to touch HTML. It's a matter of not being able to! ...
And all of these things you list are not what I do. The examples that you list have a different set of trade-offs. I'm not embedding other people's code in my GUI, and I don't expect them to take a random chunk of my application and put them into theirs. OpenDoc was a fun idea, but it didn't take off.
> What made the web as interesting as an application platform was the idea that the user agent could be extended.
I don't really know about that in the general case, I think there are more reasons than that, but in the specific case I'm certain it's wrong. The reason my company is doing what it's doing on the web is 100% about distribution. Arguably, the web stack isn't even that good for making the kind of UIs I do - but if we did what we're doing in Java, we wouldn't get any users (or investors).
I totally agree with you about openness, but openness in my space means providing good APIs and integrations with other services, not allowing user stylesheets. A user stylesheet for my app would mean a twenty page list of weirdly interdependent CSS selectors, and the end result for someone who implemented it would be something like a colour theme that only works for app. Explain to me who would want that.
Sounds a lot like an edge case. Most consumer applications do not need theming.
My larger point is that when you are developing a web app, it would be much easier if the framework was designed in a way that separated the concerns of presentation and behavior of the components.
Just to use Vue as it is what I am using now and had to get a bit more familiar: you have libraries like Vue Bootstrap and Vuetify (for Material Design) which have a lot of duplicate functionality yet are not compatible with one another.
If the concerns were separated, you could have components that have a common behavior and only differ in the visuals. Less work for everyone involved, easier for developers to get started, less unnecessary fragmentation and the possibility of positive feedback cycle between different design systems.
After (a short) twitter discussion with Adam Wathan about this, my impression is that his idea is to basically never use @apply, and instead create micro-components to encapsulate your basic styles. So instead of <div class="modal"> you create a component modal, and then you can put all the utility classes in its html, and still be able to quickly change it if needed.
Honestly, the only possible place where this may make sense to me is if you have tooling that can keep a two-say sync between designer tools and programmers tools. I think AirBnB was doing something like that with Sketch?
Aside from that, honestly I am still failing to see any benefit. If you are tying yourself to a JS codebase, you can still do that whole "utility classes at the component level" with plain SASS and global variables and mixins and you still don't need to put class definitions in your HTML.
Let me see if I can draft a quick Vue example:
<template>
<button><slot></slot></button>
</template>
<script>
export default {
name: "my-button"
}
</script>
<style lang="scss">
@use "my/sass/variables"
@use "my/sass/mixins/buttons"
button {
@include buttons.rounded($variables.radius-button-small)
@include buttons.colors($active: $variables.primary, $background: $variables.primary-accent, $disabled: $variables.disabled)
}
</style>
No Tailwind required. Easy to customize. One central place to organize your style and - most importantly to me - no css classes shoved in the HTML!Now, someone might ask for "a large button inside the hero section from the home page." Let's go about that...
<template>
<div class="hero">
<p>Welcome to the beautiful site</p>
<MyButton>Sign up now!</MyButton>
</div>
</template>
<script>
import MyButton from './my-button.js'
export default {
name: "hero",
components: {MyButton}
}
</script>
<style scoped lang="scss">
@use "my/sass/variables"
div.hero {
button {
width: $variables.size-button-large-width;
height: $variables.size-button-large-height;
}
}
</style>
Really, I am yet to understand what I am missing by taking this approach. The example above is contrived, but I don't see why more complex widgets and even whole pages couldn't be done this way. The mixins are the place where you can have all of the abstraction you want, you can even add some logic depending on the values from the variables.So, let's take a look at the benefits:
- If next week the frontend team decides to switch from Vue to anything else, the SASS code does not need to be touched at all.
- If next week the design team brings a whole new "Design Language", the JS code does not need to be touched at all (unless of course the design system also brings new functionality)
- The styling could even be verified on a series of static HTML pages. If the designer does not do any code, they can verify if the implementation matches the designs by opening a reference template, no need to run a whole JS app.
Downsides:
- If you want the code to be truly portable, your SASS need to follow a standard convention of @mixin names/parameters as well as variables. Honestly though this IS what I would expect from a "CSS framework", so I am not even sure it's a bad thing.
- You don't get to put any hip CSS-in-JS framework on your resume.
Also on bigger project you're almost guaranteed to have someone on the team who will insist on naming their classes in totally unintuitive way, or you'll end up with .big-blue-button that will at some moment end up red actually because they've been in hurry and forgot to rename the class.
One of the biggest benefits from using the frameworks is the standardization and uniformity, you're guaranteed that everyone on the team now or anytime in the future will know exactly what classes/mixins/variables are available and will have a documentation on how to use them. You need extra people to meet the deadline, you just hire devs who know the framework and you're good to go, no extra onboarding needed to explain where the buttons variables are located, and where to apply which, and how to name their classes, etc.
On the technical grounds, you are right that the biggest thing against jQuery was that it operated on the global context and that made large codebases messy, and that CSS alone might lead to a similar experience.
But I am not talking about CSS, I am talking about having an organized SASS framework, which can provide the utility classes (mixins) and which then your code would be organized by "base elements/components/pages" along with variable definitions.
The approach I am using and suggesting does require a certain discipline. It will also require that the whole team conforms to the idea that no class should represent presentation directives. But in my view this discipline not only would be beneficial in the long term, the separation of concerns would improve the chances of making reusable components and design systems that are easier to improve on its own, separate from the specifics of each underlying website/webapp that tries to adopt it.
This is the clearest concise explanation of this I've seen, thank you.
That you frequently have to add <div>s in your HTML in order to get CSS to lay stuff out correctly is enough evidence for me. :)
I'm trying not to make this too much of a dogmatic discussion, but is the cultural norm among developers going to be to just throw their hands in the air and say "styling is hard, let's go shopping for divs"?
On the one hand, I get that most people nowadays see HTML and CSS as object code, and is not that important to be abstraction that people think in. However, current web application frameworks can not solve problems that desktop GUIs frameworks have already solved in the 90s and no one is asking themselves "is this really the way to go forward?"
The experiment failed though, we've been trying for over a decade. You can't let one group write the HTML and one group write the CSS (with the pipedream being the designers writing the CSS). The only way to make complex designs is to modify both as you develop. They're too intertwined and CSS alone isn't powerful enough to do everything you want.
Keep your actual data like blog post content, blog post meta data, images etc. separated but it's 1) not practically possible and 2) there's no significant benefits to keeping your CSS and HTML separate besides sticking to dogmatism "best practices" that haven't panned out.
Also, it's not a matter of strictly separating the groups of people doing one task or another. It's a matter of being able to extend in one dimension while keeping the other untouched.
> They're too intertwined and CSS alone isn't powerful enough to do everything you want.
I'd argue that is precisely backwards. The reason that we don't see any more different designs and more bold experiments is because we are not defining the interaction points between different layers in the development stack.
If most developers keep this mentality that all they need to do is to get a system that solves their immediate problems and solves their own unique solution, then all they are going to do is this mushing together of their structure and their presentation layers, and all we are going to get is a pile architectures are going to converge to different local maxima. If instead we don't take the easy way out and make things with flexibility and extensibility in mind, then the likelihood of it becoming the basis of something ground-breaking grows enormously.
> Also, it's not a matter of strictly separating the groups of people doing one task or another. It's a matter of being able to extend in one dimension while keeping the other untouched.
Have you worked on a website with a complex web design? If you know how to do this where you write the HTML with only semantic markup tags then don't touch it again while you style it with CSS, you're breaking new ground because nobody has figured out how to do this.
That's why Tailwind, Tachyons, Bootstrap etc. exist and continue to evolve - nobody has figured out the best way to do things yet. The MVC style you can do in other languages just isn't practical with standard HTML and CSS and it's not through lack of people trying. CSS has rapidly been improving the last few years but we're still a long way away from being able to avoid e.g. adding a wrapper div or shuffling HTML around to solve CSS issues.
> all they are going to do is this mushing together of their structure and their presentation layers
I think the issue here is you think HTML is for structure only and CSS is for presentation only, when the practical reality is HTML is mostly part of the presentation layer as well because CSS alone isn't powerful + practical enough.
Large websites already store their page titles, page content etc. in a structured CMS database. What tangible benefit are you getting by pushing to separate structure and presentation more than this?
For non-web apps, how is structure and presentation split up more than this and how does it differ from web apps?
No, I said that I style it with SCSS.
I can give you all the utility classes you want - in the form of mixins. Then all your site styling and components can be defined in terms of these mixins.
I said that I am not against Tailwind in general. What I don't understand about it is the idea of having already all the mixins and utility classes and then letting people stick those in the HTML.
> What tangible benefit are you getting by pushing to separate structure and presentation more than this?
Go take a look at the template sites like ThemeForest and CreativeTim. Some of the templates look actually quite nice and could be an excellent starting point for a project. What they all have in common is that you have 5 JS technologies and maybe 3-4 different styles and they sell each permutation of these as a separate "bundle".
Then you actually download the thing and start working with it. You find out that some older versions will use Bootstrap 3, some will use Bootstrap 4. Some of them have their widget implemented with an outdated jquery plugin, but the rest is with React/Vue. And then you realize why no one makes big projects out of these things, because it requires an all-or-nothing approach when it is not necessary.
In my fantasy land, we get javascript UI component libraries that are standardized and a separate set of SCSS implementation of "design languages". So when I am writing an app and I want to have, say, an autocomplete that looks like Material Design, I can import only one widget and one "theme", instead of hoping that some React/Vue/Angular/Nuxt/Svelte/JS_FRAMEWORK_DU_JOUR has already implemented components following the style of Material/Bootstrap/God-Knows-what-Design-Language-is-fashionable-today.
Yes, I've paid lot of attention to CSS Zen Garden. No, I don't think it should stay out of HTML.
You don't have to like it, it doesn't have to fit the way you like to work. But don't try to paint it as if people who prefer having utility classes inside HTML are just somehow not familiar with idea that they should be kept out. That's been the default view for the past 15-20 years, you know?
And you're likely using IDs and classes already to target, so instead of typing the name in HTML and the styles in a stylesheet, why not just condense into typing the style as a class name in the HTML?
This carries you pretty far while you can still customize as necessary. I do skip tailwinds when I'm not working in a component framework since I can type less verbose CSS, or if there's a complex situation that needs more control.
Because the style may change, but the underlying data won't. I know that nowadays everyone default architecture is to have data coming from some json API and that will have to be processed and rendered in the client anyway - but it is not just because something is the common case that it is the only case.
By looking at the discussions, I am starting to realize that most of the people that are okay with mixing HTML and CSS have only to work with one application to be worried about. If that is the case, then yes, it gets obvious why people want to treat everything as object code.
Consider different scenarios, though. Think of how many APIs could've been avoided if we actually looked and said "HTML is data content and structure, and CSS is presentation, so why can't the HTML be the API? The microformats people have been clamoring for this for decades already, yet no one listens. How much fragmentation could be reduced if we had half-dozen frontend developers saying "we are going to build a JS component library that is strictly about behavior so that anyone can style however they want with CSS"? All of those man-hours wasted reinventing wheels just because there is an unnecessary coupling between component structure and styling, penny wise and pound foolish.
It's almost as if companies don't want to have their data easily accessible outside of their own sites and if developers actually want to spend their time reconfiguring databases and creating ever-growing Rube Goldberg machines for their own fun and profit...
What's the difference? It's the same typing, whether you create styles in CSS or just class names in the HTML. Designing the first time vs changing it later is the action.
The rest of your comment seems to be ranting other issues. CSS can't be split, that's the point. It's been tried often but it just doesnt work in reality and is part of HTML which also covers presentation concerns.
I don't see what JSON APIs have to do with this. It's not the most common case but it does actually mean you have an API to use without the presentation if you really want it, so isn't that exactly what you're asking for?
Take a look at https://news.ycombinator.com/item?id=25155424 and tell me where the CSS is inseparable from the HTML? Or where would one have to change the HTML structure if the designer decides to change the styling of the component/page?
I am genuinely curious to get some feedback about it. I'm working on this project where I am dealing now with frontend stuff and I do want (need) to make it as easy as possible for others to integrate with their systems. If there is anything wrong with my approach I'd be very pleased to find out earlier than later.
What happens if you want a different styled buttons? What happens if you put <button> inside different tags or different order? What happens if you need to change a single <button> specifically?
The complexity of cascading rules and specificity and HTML structure is what makes the reality so different than this ideal. But if you can really keep everything flat with simple modifier classes, then that's exactly what Tailwinds already does for you.
My example shows precisely how untrue that is. The buttons got different styles without having to change anything in the html structure.
> What happens if you put <button> inside different tags?
Then you define the corresponding rule. With SASS that is almost too easy. Also, don't forget that the C in CSS means cascading.
> different order?
display:grid, grid-template and even position:absolute if you need.
Do you think it will be too repetitve? Make a SASS mixin that defines these for you. Not only you're still keeping CSS separate from the HTML structure, it will very likely work in the same way that all of those "pull-x" and "push-y" rules are doing anyway.
> single <button> specifically?
I am not against using classes and ids that define purpose and even state (for the odd case where the attributes are not enough/non-existent). What I am against is the definition classes that are mapped to the presentation. You can have a <button class="critical-action-trigger"> all you want, but please do not make <button class="size-huge red">.
Likewise, if the "fire all nukes" button is so special, it deserves to be represented with <button id="fire-all-nukes">.
> then that's exactly what Tailwinds already does for you.
I said above. If tailwind was only providing a bunch of utlity mixins and variables that I could then @import to my SASS, I would understand. What I don't understand and do not want is to have classes that I am supposed to be writing inside the HTML.
The reason that I don't want that is not out of "purity", but rather because this lack of separation of concerns is leading us to a sub-optimal solution and forcing every frontend developer to reinvent component libraries every time they want to do something that is non-standard.
If we had a 100% style-free "standard" component library and the CSS designers focused only on implementing their design languages against that standard, the chances of us getting a more paretto-efficient basis for frontend development would grow immensely.
Nowadays, every frontend developer either needs to do everything on their own or hope that there is already a combination of JS component library + design language that is acceptable. If we had my way, everyone could then start their application with the standard components, pick any design language that claimed to implement the rules for the standard components and customize only the relevant parts. Everyone's 80% of the job would be mostly done.
Cascading rules and specifying by HTML layout are hard to deal with, especially in larger projects, because that structure may change and rules can overlap in complex ways. It's far easier to just atomically apply some classes directly to your HTML. And yes, you can use Tailwind as mixins within your sass rules without ever touching the HTML if you want.
Over the lifetime of projects 'cascading' always led to headaches. There's a reason the whole BEM thing became a thing.
> Do you think it will be too repetitve? Make a SASS mixin that defines these for you. Not only you're still keeping CSS separate from the HTML structure, it will very likely work in the same way that all of those "pull-x" and "push-y" rules are doing anyway.
I used to do all that. Still do for some projects that rely heavily on SASS. But using mixins and functions and extends and whatnot adds complexity that I honestly feel I can't justify anymore. /Why/ do I want to keep CSS separate from HTML when in practice they tend to end up entangled anyways. It just reeks or cargo-culting 'separation of concerns' where really it's just 'separation of technologies that are separate for historical reasons'.
> I am not against using classes and ids that define purpose and even state (for the odd case where the attributes are not enough/non-existent). What I am against is the definition classes that are mapped to the presentation. You can have a <button class="critical-action-trigger"> all you want, but please do not make <button class="size-huge red">.
But why? Other than 'this is the way it has always been and I refuse to change my mind'?
> I said above. If tailwind was only providing a bunch of utlity mixins and variables that I could then @import to my SASS, I would understand. What I don't understand and do not want is to have classes that I am supposed to be writing inside the HTML.
Because it works. And it's measurably easier to do, in the experience I and many others have. And because I still can't find a good argument not to.
> If we had a 100% style-free "standard" component library and the CSS designers focused only on implementing their design languages against that standard, the chances of us getting a more paretto-efficient basis for frontend development would grow immensely.
I do agree with this, I think. But day to day it's not going to happen. When someone comes up with a popular style-free standard, assuming that's practically possible and good enough to become popular, I'd happily switch to that.
> Nowadays, every frontend developer either needs to do everything on their own or hope that there is already a combination of JS component library + design language that is acceptable. If we had my way, everyone could then start their application with the standard components, pick any design language that claimed to implement the rules for the standard components and customize only the relevant parts. Everyone's 80% of the job would be mostly done.
Yes, but honestly by that logic we could dismiss any improvement and argue for some kind of ideal where HTML and CSS are not used for app development in the first place. But that's just not the reality we live in.
It is interesting how the immediate use-cases dictate our first opinions of the technology.
As I stated in one of the first comments of this thread: I am working on a self-hosted crypto payment gateway and I am providing a "Stripe Checkout" widget for those that want to set up a payment workflow inside their website.
I could do exactly what Stripe does and make one good-looking widget and just give the user the option to change some things like color scheme. But two things go against that: first, I am a terrible designer, so I am sure that anything that I come up with will not be as nice what Stripe does. Second, it is an open source project and I would rather have more people feeling encouraged to contribute their own different themes than trying to enforce "my" styling, which we already established will be bad.
What am going to do, then, if not ensure that I write the components without any predefined styling and perhaps offer an open source repository of "themes" - like CSS Zen Garden?
So, there you have it. My reason to argue for a "pure" HTML structure is not just out of some idealist out-of-touch mentality.
> When someone comes up with a popular style-free standard, assuming that's practically possible and good enough to become popular, I'd happily switch to that.
Honest question: would you pay for funding this? I think this haven't come to be is because it's much easier to sell a "turn-key" system than something that is flexible enough to get other developers to say "I could've done that as well."
No, but it's based on a use-case that is very specific and considering that it's a relative uncommon one, I don't see the point of trotting it out. Okay, so in this particular situation maybe something like Tailwind isn't ideal. Nobody is arguing that it is.
> Honest question: would you pay for funding this? I think this haven't come to be is because it's much easier to sell a "turn-key" system than something that is flexible enough to get other developers to say "I could've done that as well."
Sure. I mean, I'm close to paying for Tailwind UI, so paying for good stuff is definitely something I'm willing to do.
But I think what you propose doesn't exist not for lack of payment, but because it's just not that easy to do. In lieu of perfection, stuff like Tailwind can be a pretty good improvement over other things. No need to whine about it or compare it to some hypothetical ideal that you deem good enough for your edge-case needs.
I think it's actually easy to do it. It can be laborious, but not hard. And even the labor is something that can/should be done only once. So the only justification that I can find to not have this as a more widely adopted practice is that using utility classes is "easier" to get started. Coupled with the fact that most people don't care about making their components "portable" between different designs, and we end up with this local maximum.
And from what I can tell, most of us do care about portability and componentization.
If your experience is different, then that's interesting, but not much of an argument in itself. Either 1) we're just much worse at this than you are, 2) your use cases and projects are more unusual/uncommon, or 3) what you think is 'easy to do' perhaps is not, and perhaps you'd benefit from a more Tailwind-like approach too.
Obviously if what works for you, that's fine. I don't use Tailwind in all my projects, and in some cases wouldn't even do so if I could. And it's not like what came before is entirely unworkable.
But it feels a bit dismissive to argue that our experiences are just wrong, or that we're just taking the lazy way out.
The only serious issue I had was when implementing designs provided by an outside designer:
1. The design says this width needs to be 28 px
2. That'd be "w-7", which TW doesn't provide. Guess I'll add it to my tailwind config file.
3. Repeat ad nauseam until I broke down and added all "w-n" widths to my tailwind config from 1 to 500.
4. Repeat for min-width, spacing, border-radius, etc.
The result is that A) I get really good at converting pixels to rems to tailwind-scale, then back again in my head and B) My tailwind config is huge - the saving grace being the purge tool that gets rid of unused styles.
I've been curious what a "Tailwind Linter" plugin for Figma would look like....
And when you watch Adam's screencasts, you'll see him take a design which has some "custom" pixel values and then use his judgement to snap it to a built in size.
The modern web and pixel perfect design is a combo that doesn't mix and any good designer would know that.
Additionally, this is a good example of the tooling overstepping bounds. Developers giving feedback that their tooling can't match designs made to fit existing brand standards is naive and doesn't reflect business reality.
As a counterpoint though, I definitely see merit in Tailwind for new web-first applications where the development team can align with designers from the outset.
Many designers I have known think of consistency in terms of branding (at most). There is almost always some weird edge case that means a new font size, or unique spacing. Get enough of those, and the design system falls apart.
Some are better than others at this, obviously, but the mix has not really been in consistency's favor (though I will admit it has been improving the past few years).
While I don't disagree with your points, there is still ground to be made here.
1) If designers had a "tailwind linter" in their design tool from the start, I believe that they would be encouraged to use it from the start and would start tweaking their designs from the get go to look just as good with it.
The same principle applies to code linters. There are exceptions where developers can disable a linter for specific pieces of code, but having it there encourages the code to be "constrained" in a consistent way.
2) Just because a design has a "13px" padding doesn't imply the designer thought "13 pixels is the best value here and 12 pixels is simply unacceptable". A design linter would help with the "expressiveness" of the design and when things truly are "exceptional" cases.
Note 2: I'm obviously recommending a technical solution to the problem very early in the design process, but the way I solve it now is by discussing it with the designer over a zoom call. I'll show them the design and say "does this look good? I deviated a bit, is that ok?" It almost always is, which is a win for everyone.
Basically, we're asking workaday designers to design using a tool that doesn't respect the implementation constraints, and doesn't allow them to preview at arbitrary window sizes.
Good designers will also want as few values as possible. They are creating visual system. I doub't they will want to have 20 different font sizes and padding left values. If there is fontsize 26 and 29 its most probably a mistake because nobody can differentiate the size so it has no function.
It really needs to be 28px this time for some sorta-legit reason? Fine, add a semantic class (or id) for it that's not part of your tailwind framework, kind of dropping down to "usual" CSS
After a while, you get the amazing benefit of simply being able to copy and paste HTML from one place to another - since the class names are common, you can copy HTML directly from a design mockup into your application, with only minimal extra work in templating. This is much more efficient than trying to figure out pixel-sizes in a PSD, then trying to figure out which combination of CSS classes will succeed in reproducing the visual appearance (most of the time, in most browsers...)
Take the time to communicate with the designer to define color shades/palettes, margins, typography and so on. This can also lead to discovering relations and components and intent.
With Bootstrap you have a bunch of common things handled for you out of the box (dropdowns, modals, tooltips and like 100 other things you can easily find on Google since the community is massive). You can just drop these widgets into your template and get going. Often with just 1 or 2 lines code if you're using Yarn + Webpack.
With Tailwind you're on your own for all of that unless you buy Tailwind UI and even then it's only JavaScript solutions with the libraries the authors have chosen to use and it's no where near as feature complete vs the JS widgets you get with Bootstrap, even if you only count what's officially bundled with Bootstrap.
Both of those things are kind of problematic for someone who isn't super strong on the front-end and doesn't want to invest a lot of time designing these things from scratch (a full time job in itself). Especially if you want to use something like StimulusJS instead of Alpine or Vue, since Tailwind UI doesn't seem to include any examples for StimulusJS. There's a whole bunch of folks out there (like me) who aren't building SPAs. We're just using good old server rendered templates with sprinkles of JavaScript.
With that said I still prefer using Tailwind, but it's not really near the level of productivity you get when buying a very well supported $30 Bootstrap theme (ES6 JS, Webpack, etc.) and get going on your project without having to worry about implementing every last line of JS behavior.
I'm sure Tailwind will get there with better JS support. I've seen some of Adam's tweets on how he plans to address this problem but I don't think there's a time line on when all of that will be ready to go, or if it'll all be locked into Tailwind UI only (about $250).
But don't you have the choice to not use Bootstrap's JS then, and instead use either premade React components that are vanilla JS or use React Bootstrap components if you wanted to?
I'll admit I haven't written any React code but if I Google for React Bootstrap components I find a ton of resources, even 1 to 1 ports like https://react-bootstrap.github.io/components/alerts/. I also see tons upon tons of vanilla JS React components, all ready to go where you can drop in CSS class names and you're done.
Someone not using React with Tailwind is left with basically having to implement everything on their own, or try to stitch together a bunch of libs that others have written with their own individual opinions and lack of standards. It's a much different world. It's a world where you can spend 10 hours trying to get a responsive drop down working instead of 10 seconds with Bootstrap.
I will admit, I think I never fully appreciated the intent of SoC.
The line React core team would say is that that what you're thinking of isnt "seperation of concerns" but rather "seperation of technologies".
React/JSX is good because both the HTML and JS together is the view. It's the same concern.
React seperates concerns much better because it so heavily promotes the functional programming approach and that the UI is a function of state.
So it may help to think of JSX as using a functional subset of Javascript. It's not, and that veil gets pierced pretty often, but the better you contain it, the more you can effectively use both Javascript and HTML together as part of a single concern.
Using Redux with sagas even further separates out the most side-effecty parts of it, though sagas are really heavyweight and I'm still not certain if I think they're worth it.
https://blog.isquaredsoftware.com/2020/02/blogged-answers-wh...
(You can still customize the middleware when using RTK to set up your store, same as always, so if you want to use sagas you still can.)
That said, there's a lot of things thunks _can't_ do, and for those use cases it makes sense to use sagas or observables.
You could tie CSS/JS event handlers to class and id attributes in the HTML file, but you'd have to add those attributes into the HTML file to target the right elements.
Web SoC always felt more SoF (Separation of Files) to me. There is no advantage in putting the HTML/CSS/JS into separate files if making routine changes requires visiting multiple files. React puts it all in one file, which makes me think that the concern is the Component and not the individual browser parsing libraries.
I am working on a open source payment gateway for crypto and one of the things that I am providing is a javascript library for those that want to provide a Stripe Checkout-like experience on their sites.
I started doing this in vue.js, which has the idea of the components where you define the html, code and style together in one single file.
My problem is, I want the user to be able to have the styling of the checkout widget similar to their own website. So I want to have my HTML as simple as possible and let them provide the CSS. I could even try to help and provide some different ready-made CSS (to be used directly) or SASS files (if they want to customize) but I've given up on trying to do that inside of vue component definitions.
However, aside from requiring a very specific tech stack, it doesn't solve the problem of every component potentially having slightly differing styles. There's ways to handle this, but one thing I like about Tailwind is that the defaults are stronger across components, while still leaving space to deal with all the one-offs.
The question is not "semantic" or not. The question is whether your HTML depends on your CSS, or the other way round - and that depends on what you're doing.
Halfway down, it feels like we've somehow managed to recreate the OOP inheritance vs composition debate in our stylesheets (with @extend as an example of inheritance).
To me it depends on what you're actually writing - if you're making a reusable component for other people, say a custom DateTimePicker, then it's much more important to be able to restyle the thing Zen Garden-style, than if you're running the front page of your own organisation and want things to look exactly like your house style.
I'll often end up with 50 similar, but different looking buttons.
On the other side when using a component framework, re-implementing all components when there are solutions already available (i.e. very similar in terms of look and feel Ant [1] or even Material-Ui [2]) sounds counter-productive.
Didn't you stumble upon such issue? How did you handle this?
.button { @apply rounded-md bg-gray-600 hover:bg-gray-300 text-white; } and then inline you might use class="button px-2 py-4" or similar to create specific styles. Of course these could be abstracted again to .big-button .small-button etc.
Tailwind has changed not only how I write CSS but how I think about writing front-end code completely - it's really great once it clicks.
Atomic/utility-first CSS doesn't mean that you shouldn't make classes. It just means that you should make them where they make sense. Don't make a new class just to add a margin to something,or whatever. If the margin is literally all this element needs, use the utility class directly. If it's the only place you'll use this combination of classes and naming the combination doesn't add anything, you might as well just keep it inline.
But if you find yourself repeating a bunch of utility classes, make a class with a semantic name once you start seeing the pattern. In some cases, like buttons, you might see that pattern before you've even started. That's fine. You should definitely have a button class (or three).
What you (probably) shouldn't have a is .info-page__navigation__aside__second_button that just includes the button class and adds a margin, or whatever... like we did at my old job. Urgh. I refer to this as "might as well be inline CSS" - making extremely specific classes that are only used once. If your CSS classes aren't reusable, all you gain from not having it inline is the joy of maintaining two text files, and manually look up the cross references. Tailwind solves this perfect, IME.
Only if you are using a component framework or something that works like it though. Otherwise you should make semantic-style classes, yeah.
It‘s ad-hoc because you can not predict what a class contains (tailwind classes) or how it is spread through your codebase (BEM classes)
https://tailwindcss.com/docs/extracting-components
I don't understand what you mean by ad hoc. It's a very structured approach. When utility classes don't work, you make a semantic class. If that doesn't work, you make a component. You can even use BEM naming if you want, you'll just be making a lot fewer classes.
They're all gone. Vanished completely from the website. And I was half-way through!!! Now they link to somebody's youtube channel for random Tailwind stuff rather than the nice walkthrough/tutorial that were the originals.
https://v1.tailwindcss.com/course/setting-up-tailwind-and-po...
There's a version selector in the upper right corner.
https://www.youtube.com/playlist?list=PL7CcGwsqRpSM3w9BT_21t...
When you have things nested it gets out of control really quickly.
Are there CSS frameworks that help with responsiveness, and work well with templating, but are designed to work exclusively with SASS/SCSS and not leave utility classes visible in the compiled CSS? Preferably something that doesn't start with "let's make h1 and p and ul all completely unstyled", and instead has reasonable defaults that let HTML work like HTML?
The whole point of CSS classes is that they don't map to fixed styles, so they offer a useful abstraction, allowing you to change the CSS class definition once and effect all elements it applies to.
If you need to globally change the margin that mt-2 adds, you only need to change that class instead of all HTML inline styles.
I can't agree with this more. It is almost punishing in how it enforces consistency. You really have to try to move outside the consistent default it has set and if you find yourself having to do that, it should be setting off alarm bells.
I do think it has to be used with a component system though. It provides the context that people miss when you don't have nominal class names anymore. It even encourages something close to styled components I find you have very small components that do one thing.
Ideally, you don't have composite `.btn` classes. You simply have a `<btn>` component which encapsulates appropriate Tailwind CSS classes in the component (no external CSS, `@apply` required).
With this framing, `@apply` is the less preferred of 2 approaches. It's good, even necessary, in some situations, but generally you should seek ways to componentize vs. abstracting compositional classes.
The way I see it, @apply is like a mixin, compared to CSS atrocious global inheritance. I tend to start with components (and 'micro-components') with all the Tailwind classes, but if I start seeing an obvious pattern I will consider using @apply. In practice, that's worked out very well. It really seems to help with not abstracting too early or too late.
I mean, I get it, it isn't something most people care about, but I still value them.
I felt it was at the wrong level - a technical one. HTML and CSS are different technologies, but the domains we should be separating are logic and presentation. These don't always map, e.g. there is such as presentation logic.
I know the general sentiment towards Tailwind is "I spent years getting my separation of concerns with HTML/CSS down, but now you're telling me all that is backwards and CSS Zen Garden is blasphemy?" I was in the same boat. Tailwind just felt wrong, and with 15+ years of experience, I've come to trust my intuition. After watching several videos, and reading all the canonical articles on Tailwind, I still wasn't convinced this was anything more than a fad full of bad practices.
But the one thing I'll let trump my intuition is curiosity. So I used Tailwind on a medium-sized project for a couple months and was blown away by the productivity and maintainability. It took using it for a couple weeks to "get it". I had a positive ROI on this project, even considering the learning curve!
If you still think "Tailwind feels wrong, what am I missing?" I'd suggest reflecting on the following:
1) You probably haven't actually delved into Tailwind on a non-trivial project. I understand learning a new framework isn't a trivial undertaking, but it's the only thing standing in your way of discovering your "truth".
2) If you feel Tailwind is too much like inline styles, think of the difference between the infinite possibilities of strings defining a "type" vs. a discrete enum type. Tailwind classes are the enum type values.
3) If you're struggling to abstract reusable higher-level classes/components, the problem might actually be with inconsistent and non-modular design, not CSS tooling. If every page or section is a "unique work of art" then you may have poor UX/design.