DEV Community 👩‍💻👨‍💻

Discussion on: TailwindCSS: Adds complexity, does nothing.

Collapse
 
skttl profile image
Søren Kottal

A few months in you need to add another component. Designers says it should look completely like your chat-notification. What do you do? Duplicate the styles, or rename your "semantic" class to something more generic. (By the way, class names is not and can not be semantic .chat-notification is not more semantic than .with-box-shadow).

And where is the seperation of concerns / html is for content arguments when doing ".with-box-shadow" classes?

Thread Thread
 
brianboyko profile image
Brian Boyko Author

What do you do? Duplicate the styles, or rename your "semantic" class to something more generic.

Naturally I choose neither.

First, let's look at plain CSS, no preprocessors, no CSS-in-JS, just the tools we've had since the beginning of the century.

This is actually a very good use case for writing a utility class like "with-box-shadow" -- when you have reusable code. It doesn't remove the need for semantic classes to tell you what something is and keep one component separate from another.

And where is the seperation of concerns / html is for content arguments when doing ".with-box-shadow" classes?

I'll admit that having 'with-box-shadow' does violate separation of concerns, and if I really want to be a semantic stickler, using just standard CSS and HTML, I'd have to rewrite the same code in multiple places, duplicating, as you said, the code from one semantic class to the other.

I'm not a semantic stickler, and in this case, wrote a utility-class because it A) made sense, B) was limited, C) there were no better options. As I said, I'm not opposed to utility-classes. I'm opposed to a philosophy that all classes should be utility classes.

But thank goodness that in the real world, there are better options - preprocessors and CSS-in-JS! Either allows you to reuse bits of code more idiomatically. (and use functions, too, making it even more powerful.)

If I'm using emotion/css or another CSS-in-JS solution, for example, I wouldn't have a with-box-shadow class. Instead, I could extract the code to a variable: 'boxShadowCSS' or '@mixin hasBoxShadow' That new variable could then be interpolated by both .chat-notification and .new-component's own definitions, like so.

/* SCSS */
@mixin with-box-shadow {
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
    0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.chat-notification {
  @include with-box-shadow;
  /* rest of code */
}
.new-component {
  @include with-box-shadow;
  /* rest of code */
}
/* HTML : 
  <div class="chat-notification"/>
  <div class="new-component"/>
*/
Enter fullscreen mode Exit fullscreen mode
/* CSS-in-JS (emotion/css) */
import {css} from 'emotion/css';

const withBoxShadowCSS = css`
   box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
    0 10px 10px -5px rgba(0, 0, 0, 0.04);
`
const chatNotifictionCSS = css`
  ${withBoxShadow};
  ${/* rest of code */};
`
const newComponentCSS = css`
  ${withBoxShadow};
  ${/* rest of code */};
`
export const MainComponent = () => <>
  <div className={['chat-notification', chatNotificationCSS].join(' ')}/>
  <div className={['new-component', newComponentCSS].join(' ')}/>
</>;
export default MainComponent;
Enter fullscreen mode Exit fullscreen mode

Tailwind wouldn't actually solve the problem, the code would just end up looking like this:

  import tw from 'twind'; 
export const MainComponent = () => <>
  <div className={tw`p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4`}/>
  <div className={tw`p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4`}/>
</>;
export default MainComponent;
Enter fullscreen mode Exit fullscreen mode

To which I have to ask - if the designer says that they no longer want it to be exactly alike, that they want the new component to not have a drop-shadow, which one of those "shadow-md"s are you going to delete?

Thread Thread
 
skttl profile image
Søren Kottal

So you did actually duplicate the code into .chat-notification and .new-component.

I think a lot of the knee jerk reactions regarding seperation of concerns comes from something we all learned was the right way, but never really adhered to anyway.

As you see yourself, .with-box-shadow is not a good way to seperate concerns, neither is .col-sm-4, .card, and other often found classnames.

Tailwind to me is about accepting the fact, that completely seperating concerns between html and css, is at best an academic approach, and in most cases completely unnecessary for most projects. Often adhering to this is creating a much larger burden on the developer for little to no gain.

The author of Tailwind, Adam Wathan wrote this article about utility css and seperation of concerns. , that I really think you should read.

I'm not trying to concince you into using tailwind (or other utility first methodologies for that sake), but at least acknowledge that this methodology works wonders for a lot of people. At least you could append "for me" to your title.

To me, Tailwind removes complexity and adds function. My team now has a well documented vocabulary for building nearly anthing. Before that we had CSS scattered all around (thats not CSS' fault, though 😉), and different naming strategies across different projects. A .card could be named .article, or .box (or something semantic) depending on the project, and the mindset of the developer implementing it first. In tailwind it's just utilities, and I can onboard a new developer to an existing project in no time, and never fear that a change in one place, breaks something completely different in another place.

Thread Thread
 
brianboyko profile image
Brian Boyko Author • Edited on

So you did actually duplicate the code into .chat-notification and .new-component.

If, by "duplicate", you mean, I created a const variable with the data, and then referenced that variable in two places... then yes, I guess I did.

But isn't that the whole point of variables? Especially const variables? To make it so you don't have to type out the same thing multiple times?

Tailwind to me is about accepting the fact, that completely seperating concerns between html and css, is at best an academic approach

It's not an academic approach, it's a "best practice". As in - used in practice, not in theory. It's not academic at all. Using semantic-only class names is the best practice. A close second - a "second-best practice" if you will, is using utility classes sparingly. Using nothing but utility classes is a "worst practice."

at least acknowledge that this methodology works wonders for a lot of people. At least you could append "for me" to your title.

I think that the methodology might work for some people, but not for people developing professional quality software in a professional environment, for the reasons I've stated. If you want to use this in your solo side-project or hackathon app, go right ahead.

Regarding Adam Wathan's article...

I don't know what to tell you. The point he starts with "dealing with similar components" as a dilemma -- I get it. There is no way to do that without duplicating code in regular CSS.

It's the limitation of the scripting language. It's like trying to write a function in HTML, you just can't, it's not built for it. CSS isn't built well for code reuse. I wish it was. So in order to solve these problems CSS preprocessors like SASS/SCSS were developed, as well as the myriad of CSS-in-JS solutions. It solves the problem of "not being able to reuse code" directly - by allowing you to set variables and functions so that you indeed can reuse code.

I often feel like the goalposts keep shifting here. To clarify: Yes, I would rather take the problems with duplicated code in plain-CSS and keep semantic classes, than the myriad problems with Tailwind. However, all of the problems that Tailwind claims to solve already have been solved by other tools and they don't introduce the problems that Tailwind introduces.

A metaphor: say that in the 1990s, the only way to build a house was to bang nails in with a flat rock (CSS). And then, around the mid 2000s, a really smart guy invented "the hammer." (Sass) It took adjusting, and you have to learn a new tool, but it did the job much better.

Around the early to mid 2010s, another guy invented the nail gun (CSS-in-JS/Aphrodite/StyledComponents/Emotion, etc.). It worked even better... but it required power and a steady hand, and you had to be careful with it. It was (computationally) expensive too, so a lot of people stuck with the hammer because it was working fine for them. Which was okay. People would often use a manual hammer when the manual hammer seemed appropriate, and the nail gun when they seemed to need it. And all was good in the world of carpentry.

Then in 2017, someone came up to the carpenters and said: "Hey, see what happens when I do this!" and starts hammering in nails with the butt end of a loaded revolver (Tailwind). Look at how much better this works at hammering in nails than banging them with a rock! It's like a miracle!

"But it's a loaded gun. It might go off and shoot yourself"
"Hasn't happened to me yet."
"Why don't use use a hammer? Or a nail gun?"
"I don't like hammers or nail guns."
"I can understand why you might not, but even if you used a rock, that would be safer in the long run."
"Ah, but a rock can end up marring the wood."
"I'm not saying to use a rock. I'm saying that the hammer already solves the problems you have with the rock, but even the rock is a better tool for this than a loaded gun."

Thread Thread
 
neophen profile image
Mykolas Mankevicius • Edited on

You do like your strawmen don't you?

import tw from 'twind'; 
export const MainComponent = () => <>
  <div className={tw`p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4`}/>
  <div className={tw`p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4`}/>
</>;
export default MainComponent;
Enter fullscreen mode Exit fullscreen mode

Imagine for a second that React could use components, I know it's not possible, but just imagine, and your strawman code would become like this:

import tw from 'twind'; 
export const MainComponent = () => <>
  <ChatNotification />
  <NewComponent />
</>;
export default MainComponent;
Enter fullscreen mode Exit fullscreen mode

If only React or any other js framework would have the concept of components. How beautifull the world would become, right? Maybe one day we'll be able to write code like this, but most likely not for years to come!

And CSS isn't built well for code reuse. is also wrong.

All the utility classes are there in the css file, once. And are being re-used by all these different components. Which makes the final css tiny, and those CSS classes, wait for it... re-usable. OMG, WOW, SUCH IMPOSIBILITY.