But wait, what exactly is so hard about doing something like
// _profile.scss
.profile-card {
@extend .m-5;
// several more lines of extending
@extend border-gray-light;
}
and just get the best of both worlds? That variant also has the advantage of letting us JS folk use element classes for useful stuff, and makes changing all instances of "profile-card" simultaneously a lot simpler.
I was wondering that as well. By that point, though, I've never found a point in using utility classes when I can just go to the file for my current component and edit it directly. Just writing specific CSS for my components and page-layouts while using shared variables has saved me way more time than any CSS library I've used. 99% of CSS libraries are full of problems
I think for css classes like ".profile-card" this approach makes a lot of sense. Tailwind has @apply, which is a great way to turn these utility classes into named css classes.
However, after a while your app will end up with classes like .profile-card--inner, .profile-card__wrapper, and .profile-card__inner__wrapper--horizontal. When that happens it's usually easier to use those utility classes directly in the HTML template. You'll end up with something like:
<div class="flex items-center mb-4">
</div>
It's quick to write and requires no context switching!
I don't get it as well, I just looked at Tailwind which is mentioned and it just seem to be a collection of css soup which don't mean anything, I think I would be lost quickly in a codebase with only this css soup.
Most of the people commenting are missing one of the major point in "functional CSS": Keep specifity low = lower code size, less side-effects, higher maintainability.
Yes, you add bits of complexity in the HTML, but you also gain almost no specifity on the CSS side.
Could you elaborate on this more? All three of these points seem counterintuitive to me.
1. "profile-card" takes fewer bytes than "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light", so the space-savings of not defining profile-card within the CSS seems to be lost the more you reuse semantic styles within your HTML.
2. "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light" and "profile-card" should amount to the same CSS styling applied at the same level of specificity in an apples-to-apples comparison, so I'm unsure about side effects. Are you saying that using exclusively functional styling you can count on naming conventions to know if two styles would conflict?
3. "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light" looks a heck of a lot harder to maintain than "profile-card" once I have 50 profile cards in my application styling, spread out across multiple app development teams (and even development languages).
Are you saying it provides other maintainability benefits which are cross-cutting improvements that outlay the ability to think of your HTML as being made up of semantic components? Or are you saying that you are relying on component frameworks which make component definition in CSS a duplication?
1. Think about this: You have to write or customize .profile-card for every project, with "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light" you're writing 0 lines of CSS. Zero. All your CSS will be your utility framework (sizes around 5~15kb) and it will never increase in size. Now, tell me you never seen a two year project where CSS alone reached 2+Mb because at every edit someone added another class to the list...
Also: When you gzip your HTML those repeated classes will compress pretty well.
2. Yes, you're right! Same specifity for the example in question. My point was more in general. Think @extend[0], nested selectors in SCSS. They look less scarier than "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light" but they do not always do good.
And I can tell you'll have no side effects: If you look at the HTML only, what ".profile-card" does? Does it add padding, typography, borders, transitions? How do you extend it? I can't tell. But I know for sure that "m-5" will add margin and margin only. "bg-gray-darker" will add background-color and background-color only. And so on. Every class does only one thing. They don't overlap. Once you memorize the simple naming convention you can't go wrong.
3. Why it looks harder to maintain? Do you all really get scared by a few, readable, classes? Also, classes are no meant to be semantic or content-dependent[1].
At the end, I don't want to defend to death this practice. Maybe it's a concept that is hard to explain (and the OP tried a bit lightly) but I assure you, there are concrete benefits in using this approach. Many may not like it, and it's completely fine, but it's not the hell most of you are shouting here.
> At the end, I don't want to defend to death this practice.
I tried to phrase things such that I didn't seem to come across as aggressive. We all have such limited views of the world, and opinions are an expression of those views. I found attempting to understand other opinions can widen your own viewpoint, sometimes in surprising ways :-)
My expectation of what people would give as their three benefits are as follows:
1) abstraction of CSS - CSS is not especially crafted to be readable, and you typically need to code workarounds for older browsers using legacy/vendor styles and progressive enhancement. Merely using a functional CSS framework can make the CSS much more readable than manually specifying style information.
2) DRY/directness in component frameworks - if I'm abstracting a profile card into a component, there is little value to stylize based on a profile-card class, especially if that means my style is now separate from the rest of the component definition.
However, if you are not using a component framework but instead using something like templated HTML pages, you really do worry about whether people will identify a particular piece of markup as a profile card or the like, or that profile cards on one page will start to deviate from the rest of the app.
3) (Harder for me to explain) one of the maintenance issues with CSS comes from (logical) components, selectors, and styles all having M:N relationships with each other. So I might define my profile-card styling entirely within a single selector. But I might also elsewhere say something like:
This is slightly different from the concept of side effects, but IMHO this is what makes CSS so difficult to reason about and maintain.
Use of functional CSS (and encouragement to embed styles within the HTML directly, rather than composing new classes via something like @apply in a stylesheet) means that you have created a pretty clear/classical relationship of styles to presentation.
So you might make an argument that classes should be leveraged more for semantic information, the actual styling becomes much simpler.
That sort of argument would make me wonder if there is a potential tool for those who are using templating rather than component frameworks for their buildout - a CSS lint tool that encourages you to use semantic classes, but that those classes must be composed entirely from an extensible set of functional components, rather than raw CSS.
I'm sorry, didn't want to appear aggressive either. Maybe when I wrote my comment I was influenced by the great number of negative comments here, but obviously, nothing personal!
Maybe there is a lot of confusion also because the naming of this methodology. The whole "functional" thing. It's funny that the very same practice has also been called "Atomic CSS" and "Object-Oriented CSS (OOCSS)"(!).
I would name it "Non-Cascading Style Sheets" because the whole point is actually giving away most of the "C" in "CSS".
I was also thinking that another point of such negativity may be that to use it you have to somehow master all the CSS rules, where not-so-experienced developers may rely on some "trial and error" or some bad pratice (eg. adding many nested selectors) to achive the same result. I might be wrong.
I remember that there are tools that throw a warning when a class is mutated (ie. overwritten by another rule) because you don't really want to - let's say - add a border when using something like "bg-gray-darker".
Yes, this practice can be a great choice for component frameworks. But it's also great for rapid prototyping and designing UI components or whole web pages directly in the browser.
And for templated HTML pages you can be more expressive using something like
Where the "profile-card:" bit has no effect on the presentation but gives the code reader an insight of the markup.
I actually used to do something like this at first during prototyping/designing, but then I stopped. Maybe just because at some point I became so accustomed that I was able to catch every part of the page at first sight.