In defense of functional CSS
mikecr.it
mikecr.it
The real kicker:
> "I don't want to have to repeat the same 20 classes on every single button." That's understandable. I will say that there's a chance that repeating those 20 classes can actually be somewhat valuable, because when you get into a situation where one of the buttons needs to have slightly more margin-top than the others, then it's easy to fix.
That's just... bizarre, sorry.
It's infinitely better programming practice to use a "button" CSS class, because then every time you want to tweak all buttons on the site, you tweak it in one place. With 100 buttons in different places, can you imagine the maintenance nightmare?
The author suggests creating button HTML templates instead... but why? That's what CSS already does. And when one button needs more margin or whatever other unique tweak... you just add an additional class so it becomes e.g. class="button button-extra-spaced".
For the life of me I can't see any advantages to the "functional CSS" described here at all -- it looks like a nightmare programming practice.
I had some reservations at first but in practice it's been pretty much universally agreed to be great for us. It removes a huge amounts of css cruft that happens over time (unable to determine which classes are still being used, where, etc), keeps colors, margins, etc. standardized through a centralized config file and prevents you from constantly bouncing back and forth between style and markup files.
.button-critical{ .btn .btn-red }
<div class="bg-white
Just accept the fact your HTML contains your styling and go with: <div style="background:white"
There was a time when people thought CSS could be used to style some logical HTML: <div class="card-wrapper"
So the day you want to change the color of your card-wrapper from white to green you can change a line in some CSS and not have to go around all your HTML or end with a <div class="bg-white"> with a green background.CSS frameworks feel like a "let's get all the shit CSS was meant to help remove and just put it in divs".
I will just say theory aside, in practice, this has worked out great for our team. In my 5+ years experience, I've constantly run across the issue of legacy code with thousands of classes, referencing potentially non-existent markup and countless one-off tweaks. You can start with the best intentions and organization in your SASS files but eventually things start to get really crufty. Keeping everything in components and keeping styles in the markup alleviates a lot of that.
You just made me realize this is why I always have a hard time every time I try a CSS frameworks.
It always goes the same way. I'm first amaze by all what they offer, how simple and quick a great UI can be made. Then when I try to use it, there's always something wrong and I hate how it goes and I always stop and goes back to the logical ways to do it entirely in CSS.
I guess I should try some CSS preprocessor, they must support heritage of CSS class I guess.
What do you do, when the button markup changes? Let's say you need to make all links open in a new window? Then you still need to change 100 buttons. It's even more common for bigger components, like the ProfileCard example. What if the markup of your ProfileCard changes?
Instead of using CSS to define your components, I suggest using some real reusable components, either using templates or JS frameworks (depending on your use case).
That's not really related to "functional CSS" though.
<button
href=".."
class="...."
>Button</button>
And when you start fixing more complex components and HTML edge cases, you will have a lot of fun [0]. This is fine for legacy code. But I don't want to deal with this in modern projects, if I can just change a single file and be sure all components are updated. As you said, this is not related to functional CSS, but it solves many disvantages of it.[0] https://stackoverflow.com/questions/1732348/regex-match-open...
hopefully you'd have a Button component in your preferred UI framework, and you'd change it once there.
I think it is more comparable to using function composition, hence the whole "Functional CSS" moniker. The idea is using multiple atomic "functions" (in this case, in the form of classes) to transform an element by composing.
Think like the pipe operator in Elixir:
other_function() |> new_function() |> baz() |> bar() |> foo()
In any programming language, the order in which you compose functions is important.
In CSS — and in keeping with your analogy — the order in which "functions" are defined is important.
Obviously, they are not 100% comparable. CSS is not a programming language.
In programming, `f . g . h` is not the same as `h . f . g`.
In CSS, `<i class="a b c"></i>` is the same as `<i class="b c a"></i>`.
In programming, the order in which you define functions is not important — it's the order in which you use them which is important.
In CSS, it is the exact opposite.
To further drive the point home: assuming the names of these classes aren't lying, what colour is the text of this element?
<div class="text-red text-blue">foo</div>
It depends on the order in which the classes were defined. This also demonstrates why "pure" is a poor choice of word when describing anything to do with CSS. Nothing here is "pure".
> when you get into a situation where one of the buttons needs to have slightly more margin-top than the others, then it's easy to fix
You can have this with semantic classnames. In fact, that's exactly what the "cascading"[1] part of "cascading style sheets" was intended to solve.
In my experience working on a web app that sees +80k DAU, the most difficult updates to our UI are ALWAYS in the cases where somebody wasnt cogniscent of the cascade. Or was, and used it when they shouldn’t have.
IMO, theres a lot of pushback to this technique and not a lot of questions into its benefits, but plenty of questions as to why its “just like this” so “why should I use it.”
I encourage you to consider the benefits of an isolated approach to UI, or perhaps try building something with it and see how the method compares to your current approach.
Or, we can all go on assuming that Airbnb, Facebook, IG, et al, have all opted into this approach for no reason
I think this is really the core of it, because CSS is kind of bad at it, and just about every project ships with more powerful HTML templating anyway.
>when you get into a situation where one of the buttons needs to have slightly more margin-top than the others, then it's easy to fix.
It's easy to fix in "regular" css too: just add style="margin-top: 10px;" to the button.
If this is really a one-off situation, then that is totally fine. Functional CSS feels like over-engineering an already-solved problem.
And this is a great example of that theory. If one had to apply the terms "over" or "under" to describe the engineering of the practice the article describes, it seems like "under engineered" would be the more apt description. This is pure brute force programming and design.
Working with CSS is fairly unglamourous. These functional frameworks don't really appear to be a solution to me. What they've done is basically take CSS and create a DSL that has to squeeze into a `class` attribute, without actually adding any extra value than what you would get from writing raw CSS. You don't really get consistency out of it. Just terseness.
This becomes even more bizarre when you see these frameworks used with preprocessors like postcss, because what you end up with then is basically spaghetti.
.some-button {
@compose mt-2 my-4 p3 border-radius flex align-bottom;
margin-right: 32px;
border-radius-bottom-right: 2rem;
&:disabled {
display: none;
}
}
At what point did all of this become an advantage?Let's review the main use case you present "I want to tweak all buttons on the site, I tweak it in one place":
- How many times do I have to change all the buttons on my app?
- Does changing one class work to change all buttons in practice? Don't I end up having the color overloaded 3 times, cascading over and leaking in 5 others spots?
- Are most of my edits in CSS tweaking existing rules, or piling up more CSS? Usually, in a large codebase, I end up just adding a class instead of tweaking one and figuring out if I broke anything anywhere.
- If I use a component-based approach, like Angular or React, do I really have to change classes everywhere with functional css, or just in the button component?
- Is styling "functional"? Can I always change the styling of a class without changing its semantics - like if I put the primary button the same as the secondary, did the naming help?
Your case may be different and our point of view may also evolve. With functional CSS + component-based approach, I rarely have to use the style inspector - and produce beautiful, maintainable app with 14KB of CSS and no styling bug. All my other attempts using CSS "the right way" lead me to 1MB+ of CSS.
The benefits of CSS to factor style by function seems very infrequent compared to the problems they introduce.
It's very easy to just make another CSS class everywhere, but that defeats the point of CSS and you might as well just use inline styles.
Clean well maintained CSS makes a huge difference. The problem is your CSS needs to map to semantic meaning of what's going on, and you need to maintain the effort to keep it clean.
> How many times do I have to change all the buttons on my app?
How about how often do you need to change all your 'submit' buttons? The HTML element type is again vastly less important than what each element means.
When making a styling change like this, it's typical to change it app-wide.
> - Does changing one class work to change all buttons in practice? Don't I end up having the color overloaded 3 times, cascading over and leaking in 5 others spots?
I can change the border-radius on all of my buttons, and they will all change, and still have their color-specific classes.
> - Are most of my edits in CSS tweaking existing rules, or piling up more CSS? Usually, in a large codebase, I end up just adding a class instead of tweaking one and figuring out if I broke anything anywhere.
This is unfortunately quite common in practice - because maintenance is hard and practices are bad. But it is definitely possible to have robust, reusable css.
> - If I use a component-based approach, like Angular or React, do I really have to change classes everywhere with functional css, or just in the button component?
Phew! A component just for a button. What a twist! I don't think most people are making components for each html element. In fact, I'd say this is pretty redundant and overengineering things in a bad way. Guess what - html has these nifty components called buttons too, and you can also style them. Wouldn't any minor change to your button component require then passing in props (just like classes)? <Button propName={"danger"}><button></button></Button> doesn't really seem better than <button class="btn--danger"></button> to me.
> - Is styling "functional"? Can I always change the styling of a class without changing its semantics - like if I put the primary button the same as the secondary, did the naming help?
Not really sure what you're getting at here.
Welcome to the world of web components. This is actually really common, especially in React with css modules - this way you can use your custom button without even having to think about the CSS (or any extra complexity like tooltips and accessibility), even from a common library used across projects.
We use custom components like this at work, and it actually works quite nicely because you get to see all the different "types" of buttons at a glance by looking at the prop types. Using the component looks something like this:
<Button label="Click me!" primary />
I've found that it's helpful for enforcing consistency, so that you have to go out of your way to apply custom styles to a button (which isn't required 95% of the time). Plus, it helps abstract things that don't have anything to do with the <button> HTML element but are often tied together, like being able to automatically make a button a link without having to wrap it in an <a> tag:
<Button label="Home" href="/" />
It's all minor stuff, but it enforces consistency and keeps you from having to think about CSS classes at all most of the time.
1. it does actually happen but more often than not, individual buttons need some changes.
2. absolutely but that's why we use SCSS to help "cascade" those changes. Unfortunately, those large changes, again, require individual tweaks in some tricky areas.
3. adding classes is always the safer approach. One thing that has helped us is to make sure classes hold little (but valuable!) responsibility.
4. this is an awesome question. So, for us, those little adjustments specified in the post (small margins and so on) were tweaked at component-CSS level while large-changes were kept to our SCSS framework
5. It's basically CSS-in-HTML
So my own experience has taught me a general approach of my own:
1. create a framework for your site in SCSS. This includes basic styles for buttons, input boxes, colors, typography, tables etc. but stay away from more complicated styles (like trying to create CSS for a "profile card")
2. keep "component" CSS inside a component. Profile card CSS goes in profile.component.scss
3. overrides/hacks belong to where those overrides/hacks need to happen.
const Button = styled('button', {/* styles here*/});
...and you get deduped atomic classes (plus proper source maps, so the debugging experience is actually pretty similar to vanilla CSS)There are also more transparent ways to leverage existing functional css frameworks. For example, Mithril.js[2] lets you use CSS selectors in templates, so you can do things like:
const Button = 'button.some.atomic.classes';
m(Button) // equivalent to <Button /> in JSX
The problem with `class="button button-with-quirks"` has to do with specificity. Yes, you can edit the base class... but then you also need to go hunting for visual regressions anywhere you have a compound class because who knows what might be overwriting your edit and how. Also, your team needs to be extremely disciplined when dealing with 7 slightly different variations of left margin on a button (and usually they are not).The two most important benefits of functional css that the post doesn't go into that are kinda important to the discussion are these:
- atomic styles can be deduped, making for smaller bundle sizes
- they make it nearly impossible to accrue specificity-related technical debt
Many of the downsides alluded in the article are solved by libraries like styletron.
At my job, we have a mid-size React app where more or less every element has one CSS class with all the styling in it. There used to be more of a framework of reusable styles, but it doesn't get used much any more because it's out of date with what our designers want now. We should fix it, but there's no time because we have to pile on more features to fix later. You know the drill, I'm sure.
But basically, for more or less every HTML tag, there's a custom blob of CSS that's only applied once. This is inline styles, we've just moved them to a different set of files.
<div class="card notice alert-colors">
Warning: frobnitz is dangling. Please address.
</div>
I gather it's because ridiculously literal styles are the only thing you can offer in an "un-opinionated" functional framework, because you'd otherwise have to engage in some styling.ETA: And even "alert-colors" could probably be "alert" or the like, if I saw the consistent need to bold the text or whatever in alerts.
I agree that this might help you move quickly when starting a project and might be a fine approach for a small prototype or personal site (or, more unkindly, in a consulting project). But you pay a huge cost: maintainability. There is no encapsulation at all, not to mention the pain of having all these generic classes floating around, colliding with anything that might accidentally match. I’ve worked on projects like this where huge HAML views chain many of these functional CSS classes. It makes it very difficult to accommodate new external components or design updates which I would say are pretty much inevitable in any product company. Even if you don’t add anything new, good luck updating the entire system to adjust the padding on all buttons unless you were disciplined enough to truly create encapsulating classes (which is really the opposite approach of functional CSS anyway).
I really think CSS modules got it right (or similar approaches where you have a unique class name per component). Our team approaches component styles like a UIView in iOS—it should render acceptably with reasonable constraints. This means any parent component / view can render this and set display: block, flex, etc and the contents should largely adapt. These days this is pretty easy with flexbox and grid. Even better—you can ensure that the markup classes stay private to you and only allow modifications through JS (or mark some classes as :global). Even better than that—your components can adopt delegation or renderProps to allow parent views to replace / modify with their own markup so everything in the component can truly be encapsulated.
I think some of this is due to the fact it was originally more about document layout than screen layout. At least the cases where I find CSS (horribly) awkward are cases where I'm trying to do something that falls more into the category of UI layout. For document formatting, it feels like a much better fit.
Agreed. Wholeheartedly.
> I agree that this might help you move quickly when starting a project
I don't even see this... at least I can't imagine a case where I'd want to replace "background: #333;" with "bg-gray-darker". The CSS has at least been well established for years/decades, and it'll be much easier to find documentation/support/etc.
> But you pay a huge cost: maintainability. There is no encapsulation at all,
He's advocating that the encapsulation happen at the level of templated markup (or JSX, whatever), rather than at the level of CSS classes.
I'd suggest that everyone read this post [1] by Adam Wathan, the creator of Tailwind CSS. It does a much better job explaining and defending than I did.
[1] https://adamwathan.me/css-utility-classes-and-separation-of-...
But my post is just a bad defense of it. The section about the separation of concerns is especially unconvincing, and I spent almost no time talking about the benefits of it. I'd like to rewrite it at some point.
Might as well just treat everything the same across the board, e.g. tailwinds and reduce the overall complexity of naming
I read many functional CSS articles but this one has convinced me to try it out
However, I still don't think it is the complete answer. Mostly, if I'm wearing my developer hat (rather than designer hat), functional CSS would drive me batty. If you are working in a larger team, where some of the team write the HTML and some write the CSS styling, this really disadvantages the people who work with the HTML. As a developer, I need to write HTML where I am semantically describing what the component is doing as I have no idea about the details of the design.
What might work is a hybrid approach? That is, designers work with functional CSS and then at the end, map the compositions back to the semantic class styling? I.e you would do mostly the same thing, but would move the functional CSS styling into the CSS and have a mappings at the end. Would this give the best of both worlds - keeping the HTML semantic, but still allowing designers to mostly work with functional CSS?
Absent this approach, in web projects of nearly any size, the CSS inevitably grows and becomes increasingly difficult to maintain. It takes very very few cases of "I'll just write a bit more CSS" as the default solution to bug fixes or changing requirements, before the best-intentioned design system becomes a brittle nightmare. Whereas functional CSS supports composition, and makes refactoring a reasonable proposition.
As a 20-year veteran of web UI development, I encourage skeptics to read Tailwind's docs, which make a better case than the OP or I are doing here.
<div class="m-5 p-5 text-gray-light bg-gray-darker border border-gray-light">
what the hell is that thing described by all those styles?versus:
<div class="profile-card">
and i know immediately what it is, and can instantly map the markup to what i see on the page.you just lose too much by not having that imo.
i really like composing styles out of small little semantic utility classes as in the first example above, but you can do that and still have semantically named classes easily enough with a preprocessor.
i'd be curious to hear your thoughts on that. when i've discussed this concern with functional CSS purists they usually just shrug and say something like "you get used to it" or "you just don't need those semantic class names" but i find that response unsatisfactory.
clean, readable markup is so much more pleasant to work with.
<div class="profile-card m-5 p-5 text-gray-light bg-gray-darker border border-gray-light">
with "profile-card" being use just for identifying the component.Other than that, I rarely go through HTML without Dev Tools, which shows me exactly what a certain div is for.
> Other than that, I rarely go through HTML without Dev Tools, which shows me exactly what a certain div is for.
I do all the time. I'd much prefer to work in my text editor, without being obliged to use chrome tools to extract semantic meaning from my code.
I'm not saying you're wrong, I think I'm more or less against functional CSS, but just saying there's at least one more way to look at it.
I weight clean markup and "knowing immediately where i am by looking at the code" more heavily in this particular balance scale, though -- it's a higher-level concern in some sense.
Practically speaking, I'd typically have the markup open side by side with the SASS (or other source CSS) file where "profile-card" was defined in vim, so the lookup process is just moving my eyes across the page.
But using classes named with colors is silly.
It's as silly as naming a function based on the content of a string it's manipulating.
const str = "cat";
function reverseCat(str){
return str.split("").reverse().join("");
}TLDR: Tailwind is utility-FIRST not utility-ONLY, and its `@apply` directive and approach to composition means you can exercise a lot of control without every element requiring so much "noise".
Don't get me wrong, I'm not saying there's only one good way to do things and this is obviously it; rather, it's worth overcoming one's initial revulsion to look at what's possible, bc it is in fact quite elegant.
I just don't want them in my html. It's really not resistance that's at work here. I just think you should name your abstractions. Note this does not imply coupling. If you're so worried about that give every element a different name for all I care, put a number at the end of the names, but at least make them meaningful. I still want to be able to read my markup.
It's odd to me that functional-css seems to have gotten bound up with "inline everything." The two concepts are orthogonal. And it seems that the big benefit of having everything in line is... you only have to have one file open?
I mean, I guess that's simpler than two files side by side, but it's such a tiny benefit compared with readable markup imo.
Huh? I think you've got it exactly backwards. My React components all have semantic names. In contrast, you're apparently using raw HTML "div" elements and relying solely on your style classes' names for semantics. You can certainly do that (with or without functional css) but it's orthogonal to the things that make Tailwind and functional css great, and your complaint makes me wonder about your setup; it's almost as if you're hand-writing and maintaining static HTML identical to what you see with "view source". Are we both talking about styling web applications?
exactly. that's what i've been saying, and why i don't understand why "inline css" and "functional css" have been conflated.
i'm not sure why you're bringing up react -- i'm talking about the general case of writing markup. obviously you sometimes might write it directly by hand, and sometimes it might be generated for you by react components or server-side components or whatever.
In web apps (as opposed to web pages), this problem is better solved by breaking up and grouping CSS with its associated components. Re-use the components, not the CSS classes.
Regarding how to keep CSS modular, just give each component a unique name and apply styles to child elements using nested selectors:
.exampleComponent .exampleItem {
border: 1px solid #aaa;
/* etc */
}
This becomes even easier in SASS: .exampleComponent {
/* put all the component's styles in here */
.exampleItem {
border: 1px solid #aaa;
}
} // _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.Additional benefit: you can nest stuff. So you card will include a nice dropshadow/border mix with you also can use on it's own somewhere else.
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! .m4, .profile-card, .other-card,
.header, .foo, blah {
margin: 4em;
}Yes, you add bits of complexity in the HTML, but you also gain almost no specifity on the CSS side.
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?
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.
Peace! :)
[0]: https://webinista.com/updates/dont-use-extend-sass/ [1]: http://nicolasgallagher.com/about-html-semantics-front-end-a...
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:
``` a, .nav .selected, .profile-card .info { color: #ed0a1f; } ```
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.
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
"profile-card: m-5 p-5 text-gray-light bg-gray-darker border border-gray-light"
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.
You reduce errors by reducing code by wrapping your code in functions, thats functional and its how classes work. This article suggests the opposite just write everything from scratch perfectly, not going to happen.
> there's nothing stopping you from continuing to add those semantic classes, even if they're irrelevant for styling If they are irrelevant to style then it could be applied to anything, it has no meaning and is not semantic.
They don't know what separation of concerns is, or why its a good thing.
>when you get into a situation where one of the buttons needs to have slightly more margin-top than the others
Yea just break your designs consistency im sure your users will love that.
I was able to give three common and specific reasons why its bad advice, none of them where to just trust me, or my experience.
If the only reason you like something is because you like it, fair enough, good for you, you like a thing. Its ok to like things, but that doesn't mean there is any solid logic backing the things you like.
The obvious result is that you would end up with similar objects with different styles. A button with "main" role should have a consistent style across instances, not be green in one place and grey in another because you forgot to add the "green" class. Also changing the color of "main" buttons from green to blue should not entail changing each usage of the "green" class to a usage of a "blue" class.
This kind of separation doesn't magically make your frontend code good, it just gives you the freedom to architect it well. Whether you do is up to you.
Admittedly it is very difficult to find an example where this has been done well, but this is I guess why we have abominations like AMP.
But the other thing is that we rarely upgrade just CSS, usually we get a whole new front end, or even more likely a whole new app.
If .login-box is now going to be larger but green, you'd normally just edit the CSS to change that.
With visual classes, you might have to modify the HTML to add/remove/change classes, then also edit the CSS. Or maybe only the HTML. Or maybe only the CSS. It's hard to know.
No you don't, you can edit the one LESS/SASS/whatever file, and rebuild to reflect the change in your custom class that mixes in the desired properties, done. Or you do the same in your HTML templating language. All of the code reuse patterns you're used to from regular programming are applicable here, and that's why it's better.
Also, if you're in a larger team with separation of responsibilities, then the UI-focused person can make the change without you without having to understand CSS. Functional CSS is considerably more flexible.
CSS is an expressive markup. You shouldn't try to turn it into programming.
Are you saying that with a CSS file with one-class-per-component it's easier to remember the hundreds if not thousands of class names, compared to a functional library, where you only have to remember a handful of them?
You might not like it, but the very reason of existence of functional CSS libraries is to limit the number of classes and improve reusability and composition.
Why would anyone restrict themselves to one class per component? Do you know that classes can be combined? Do you know how specificity works?
CSS fundamentally lends itself to being compositional. Suggesting that this isn't the case without added libraries is either ignorance or madness.
This approach sucks and you end up with "gutter-left-10 skin-primary-blue gutter-bottom-20 row-single col-3 designer-lastminute-overridehack" which is just proxying CSS into class names and does not scale or transfer to anyone you bring onto a project.
BEM is equally awful because you're encoding structural data into the class name which again is just proxying CSS.
The point of turning it into programming is to make it scale. But all those frameworks are completely missing the point (what's the problem of web technologies? They seem to always miss the point, prioritize the non-solution, and complain loudly of anybody that complains about the actual problem). A framework can not solve the scaling problem because it's a language problem, and the preprocessors focus only on expanding things, when the specificity is a larger problem than DRY.
Despite my scepticism of extremes of semantic web, I realise now when I read articles talking about switching to this style of css, their problems are entirely unrelatable to me because I implicitly see the conceptual structure of a design vs its visual specifics.
This just feels like a new age of developers don't see the need for the abstraction and so it's a constant mental burden for them without any benefit.. I think what has propped this up is that some of the problems that semantic css has historically only ever been able to solve (such as responsive) are now being solved differently, either through more powerful css layouts that implicitly layout better responsively, or that they rely instead on javascript to switch classes/html/components out with media query listeners.
Ultimately I think whatever you decide should be based on what your team aligns to best, don't feel guilty about 'not getting' this pattern, but I think it's important you pick one way, as mixing these worlds just doesn't work (at a project level), but certainly you should always try new things for new projects or experiments.
This x 100. As a guy who is the only American on a team with a bunch of non-native speakers, taking away naming responsibility is a big win.
If you're writing HTML by hand, then yes, it will be a PITA changing all those "bg-blue" Profile Cards using functional CSS (while it's just a single change when using .profile-card instead). In reality, it's not the functional CSS being the issue, but the markup duplication. If I extract a real reusable ProfileCard component, I can apply functional CSS to it exactly once. If the color changes, it's just a single place I need to look into.
There is no silver bullet. If you design web sites, try some templating language to extract your components. If you develop web apps, take any modern framework like React, which enforces using reusable components. If you still prefer writing HTML by hand, then yes, functional CSS is not for you.
[0] https://adamwathan.me/css-utility-classes-and-separation-of-...
Then you're basically moving re-use from CSS to HTML templates. And if both exist only once, it shouldn't matter where you have to adjust that one line.
My team in fact combines both approaches. I don't need to define a CSS component just to add some margin, but I am also free not to use 15 functional classes to clutter the HTML.
I make pretty heavy use of cascades and don't put classes on every single HTML tag and try and keep my HTML as semantic as possible even though I actually do have components for every button. I will put an inline style of something if that is the most logical approach but proper semantic classes allow me to work at a higher level than individual styles.
Also, from the article:
- Inline styles don't respect media queries, which basically rules out responsive design
- Inline styles aren't limited to pre-defined options, meaning you can still end up with 90 different shades of blue)
- Inline styles cause specificity issues, since they trump separate stylesheets.
- Inline styles don't support print-specific styles.
- Inline styles can't address pseudo-elements (such as ::before and ::after)
- Inline styles can't apply to multiple elements. Utility classes can define .bg-blue once and have it apply to many things, which leads to shorter markup and quicker rendering speed.
- Inline styles are a pain to type. Compare class="f-sm bg-blue" to style="font-size: 10px; background-color: #0000ff;".
I would call these "padding-small" or "padding-big" in that case. Of course, a better way would probably be to abstract that even further in actual purpose rather than style.
> Inline styles don't respect media queries, which basically rules out responsive design
I question how you could have style-like-classes like pt-10 and be responsive at the same time. So this style is padding-top: 10px as it's name suggests except on mobile. That makes no sense.
> Inline styles aren't limited to pre-defined options, meaning you can still end up with 90 different shades of blue)
That's fine. Although why limit yourself to calling the class "blue" when you could call it "brand-color" and actually be able to change it something other than blue in the future.
> Inline styles cause specificity issues, since they trump separate stylesheets.
I don't think you want your "pt-10" style to be "trumped" by another style otherwise that would be confusing. So again this is not an advantage to this style.
> Inline styles don't support print-specific styles.
Again, it would be confusing if "pt-10" suddenly didn't apply when printed.
> Inline styles can't apply to multiple elements. Utility classes can define .bg-blue once and have it apply to many things, which leads to shorter markup and quicker rendering speed.
So the advantage is you get to type 5-10 fewer characters per element you apply it to?
> Inline styles are a pain to type. Compare class="f-sm bg-blue" to style="font-size: 10px; background-color: #0000ff;".
Only if you know all the classes that actually exist for the particular project you are working on. Does f-md exist? Is really "fd-small" in this project? My editor will autocomplete inline styles so they might actually be easier to type.
>I would call these "padding-small" or "padding-big" in that case. Of course, a better way would probably be to abstract that even further in actual purpose rather than style.
This is perfectly fine. Functional CSS does not enforce any naming. In Bootstrap it's just "p-1" through "p-5". But I would rather go with more semantic names, too.
>> Inline styles don't respect media queries, which basically rules out responsive design
>I question how you could have style-like-classes like pt-10 and be responsive at the same time. So this style is padding-top: 10px as it's name suggests except on mobile. That makes no sense.
Following your example, you can have "padding-small" with different paddings on Desktop and Mobile. Which is not possible using inline styles. For Bootstrap you get media query suffixes for many classes. One common usage is "d-flex flex-column flex-md-row", which makes an element "flex", with column direction on mobile and row direction on desktop. Handy for simple use cases like that.
>> Inline styles aren't limited to pre-defined options, meaning you can still end up with 90 different shades of blue)
>That's fine. Although why limit yourself to calling the class "blue" when you could call it "brand-color" and actually be able to change it something other than blue in the future.
Again, I think you're mistaking a single Functional CSS implementation (like the one used by the author) with the concept itself. You are not forced to use color names and numbers in your functional CSS class names. And I fully agree that semantic naming is way better.
>> Inline styles cause specificity issues, since they trump separate stylesheets.
>I don't think you want your "pt-10" style to be "trumped" by another style otherwise that would be confusing. So again this is not an advantage to this style.
What the author means: using only functional classes, you know exactly that your "pt-10" padding is not overwritten (unless you use another "pt" class by mistake). With "traditional" classes, you can't be sure of that. And more often than not you will get problems with the cascade, especially in bigger projects with many developers. That's where all the "!important" hacks are coming from.
>> Inline styles don't support print-specific styles.
>Again, it would be confusing if "pt-10" suddenly didn't apply when printed.
You can do much more with CSS than adding padding ;) Hiding elements for print is the main use case here. You can't achieve this with inline styles only. A "print-hidden" utility class can do that.
>> Inline styles can't apply to multiple elements. Utility classes can define .bg-blue once and have it apply to many things, which leads to shorter markup and quicker rendering speed.
>So the advantage is you get to type 5-10 fewer characters per element you apply it to?
No, the advantage is that you can use only pre-defined, reusable, atomic definitions. If the style guide says there are only 2 types of padding ("padding-small" and "padding-big"), you won't be able to set another padding using functional CSS only. With inline styles, you can do whatever you want. This also applies to raw CSS stylesheets. That's why pre-processors are so valuable - you can define your SASS/LESS/whatever variables and achieve the same effect. And before you ask: "then why do I need functional CSS in the first place?" - it's because of the other advantages, like not having to use a pre-processor or defining/importing a stylesheet in the first place.
>> Inline styles are a pain to type. Compare class="f-sm bg-blue" to style="font-size: 10px; background-color: #0000ff;".
> Only if you know all the classes that actually exist for the particular project you are working on. Does f-md exist? Is really "fd-small" in this project? My editor will autocomplete inline styles so they might actually be easier to type.
If you don't know all the classes, then you need to know all the style guide values. Otherwise, how do you implement a consistent-looking design? Take our "only 2 padding values defined" example. You will have to look stuff up, be it functional class names, traditional class names, SASS variables or simply the values to be used. Also, my editor will autocomplete functional CSS classes, too.
Honestly at some point what you describe I would just describe as normal CSS.
Functional CSS is classes based on their visual function rather than an abstract concept. This the definition. But the more semantic your names are the less they related to an actual visual function.
If on mobile you don't apply any padding then your padding CSS class is a lie. And if you don't call it "padding" in some way then it's not Functional CSS. I also think conceptually having a few utility classes like "print-visible" or "print-invisible" is not really applying Functional CSS as an overall concept.
Composing utility classes via css (ala, what many have done for years since sass/less) is one thing, but then collapsing the component class all the way back to the html I really can only describe as jumping the shark, it's gone beyond logic.
If your class names are semantic like profile-card it's easy to have a branding css file for each client.
If your class names are functional like m-5 p-5 text-gray-light bg-gray-darker border border-gray-light you're going to... what? make code changes for each client?
Obviously if the website is only going to have one branding, this isn't an issue, but advice like "use semantic css" or "use functional css" needs to be put in context. What you do in an agency context for content sites would be different from an in-house web-app context, or a web-app for SAAS context.
And if you had a bug related to profile-card styling, are you going to find all cards to update the styling? Are you sure you didn't forget some?
This approach seems to be based on the idea that design is completely immutable after the initial conception. This is... not how design usually works :)
Is that the problem you were addressing or did you have something different in mind?
So, yes, semantic names matter, and functional names are a bad idea in the long run, because they shatter maintainability.
I like defining a few concrete component styles BEM style and having it easy to re-use them and other people not abuse them too much. After the initial components are defined I don't want to think about what border or colours are involved I just want to drop profile-cards in various places. It feels like this "functional" approach doesn't solve enough real-world use cases (that I have experienced at least) to justify using it.
I suggest reading:
https://hackernoon.com/full-re-write-with-tachyons-and-funct...
If you have lots of repeated components on a page (comments, thumbnails, tags) then it's difficult to defend repeating, potentially dozens, of the same declarations. You're better off with the component defined in a stylesheet.
I think the real use for functional CSS is for one-off adjustments on those components:
<div class="comment">..</div>
<div class="comment">..</div>
<div class="comment disabled">..</div>
It's also a pain to edit all of the instances of an object when you want to update styles consistently. One upside, though, is that you have to consider the impact of the change in each spot.That's where you have two choices:
1. Use your HTML templating language to define a dynamic variable representing the set of classes and use that.
2. Like the article says, make use of the functional CSS's tools to create a new class that includes the styles you use. Same idea to #1, just at a different stage.
And there's nothing "correct" or "incorrect" about it. I suggest reading [1] if you want some real data on the usefulness of functional CSS.
[1] https://hackernoon.com/full-re-write-with-tachyons-and-funct...
The pros of functional CSS as a replacement for CSS/SASS variables:
- You define your 'palette' up front: which margins, font sizes, colors are acceptable, etc. You could do something similar with CSS/SASS variables, but you'd give up the capability to rapidly prototype on any machine with any browser and you'd need HMR set up everywhere. Also since it's a class you can (de)compose it with other classes and build up 'abstractions'. So I'm really using functional CSS as a better replacement for SASS variables.
- It's easiest to start hacking away at designing widgets without worrying about things looking inconsistent eventually, because you're working with a limited palette
And then what I take out of atomic CSS is splitting up the code into different levels. Instead of atoms, molecules, organisms, I have: palette, abstractions, components. Abstractions are composed of other abstractions and/or things from the palette. Ie: an abstracted class might be like: .center-vertical, .center-horizontal, and then composing those would give the .center class. Components are concrete widgets like buttons, popovers, modals, tables, lists, etc.
And I use the submodule idea from BEM. So if I need to create custom themes, it would be the like .button .button-(theme name) and writing the theme works just like inheritance would here but I'd be using composition instead
Take ten minutes and learn. Here's some tips:
Attribute selector:
button[disabled]
background-color: gray
Modifiers are just classes, never have disconnected .some-classes floating around. Keep them scoped to their element : button.large, a.button.large
font-size: 2rem
Child selector: profile-card > h2
font-size: 1rem
margin: 0
Everyone forgets to put in the alligator and then complains that their ridiculously nested markup gets out of control. This way a card can contain _anything_ and not have to worry about stomping its styles.Semantic elements:
profile-card
display: block
profile-card.active
background-color: green
You don't need to be limited by span/div-itis. It's 2018 go wild.Pro-tip:tm: try learning CSS before creating or adopting a CSS "framework" to solve problems that CSS already solves.
Hope this brief rant saves a life or two. Hang in there people.
- How do you set a class for states like hover, focus, active, hidden, checked, etc
- How to you use/create/style pseudo-elements?
- How do you add responsive control (like CSS media queries)?
'Functional CSS' is like sitting down at a full piano keyboard and trying to bang out a tune by only hitting one key - there's a LOT more range possible in CSS, and it's only difficult mostly because we MAKE it difficult by ignoring this.
The only/best 'functional' CSS tooling I would even look at these days is http://css-blocks.com from the people who made Sass, it's a much more modern approach and you end up with highly optimized code, HOWEVER you write human-readable CSS stylesheets and you let the CSS-Blocks compiler and Opticss optimizer output the 'functional css' you need.
Let humans do what humans are best at (writing nice stylesheets) and computers do what computers are best at (compiling things). It will outperform and human pretending to be a compiler, and with better accuracy.
class="hover:red" -> .hover\:red:hover { color: red }
class="before:red" -> .before\:red::before { color: red }
class="medium:red" -> @media (min-width: 500px) { .medium\:red { color: red }
The important thing though is it doesn't need to be used for everything. I think it makes a lot of sense for structural stuff. When you dig into like, children of a hovered element I can see it getting a little messy.The classList API makes modifications to the class property very easily.
You'd be essentially limited to one identifier in attribute selectors. You can't really select from multiple identifiers with a data attribute without doing like:
[data-hover*="foo"]
which would search for "foo" anywhere in the attribute, which could mean incorrect substring matches.Chaining attribute selectors would be rough too:
[data-hover*="foo"][data-hover*="bar"] {}
vs .foo.bar {}So does the dataset interface for custom data attributes: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement...
> You'd be essentially limited to one identifier in attribute selectors. You can't really select from multiple identifiers with a data attribute…
That's just not true, there's an attribute selector that targets strings in a whitespace separated list: [attr~=value], so you could think of .demo as being a shorthand for [class~="demo"], or #demo as a shorthand for [id="demo"].
[data-hover~=foo][data-hover~=bar] {}
would target a tag like this: <div data-hover="foo bar"></div>
But not a tag like this: <div data-hover="foobar"></div>
More info about attribute selectors: https://drafts.csswg.org/selectors-4/#attribute-representati...The classList api is still a lot more suited for this than dataset. None of the modifications done through the dataset api would reflect in the DOM and be readable by CSS unless you were to convert the list to a space separated string and explicitly set the attribute. classList handles all of this for you.
I'm really not sure what you mean by this. If you set the data attribute any of these ways, it can be targeted in CSS with [data-demo="example"]:
el.dataset.demo = 'example'
el.dataset['demo'] = 'example'
el.setAttribute('demo', 'example')
CSS doesn't require a space separated anything. When you use an attribute selector in CSS it treats the entire value as a string, spaces included. But it's not classes versus attribute selectors, as class is an attribute, and therefore also something you can select with attribute selectors.Also, think about the asymmetry between CSS and HTML when considering saving characters, one CSS selector targets ∞ tags, so I'd rather write slightly longer selector one time, than need to use a much longer 'namespaced' value on each element where I want the style to apply. That's leveraging what CSS does best!
I use classes strictly for styling. I change these styles by adding and removing class names and classList handles it very well without me needing to read the data attribute, make it an array, manipulate it, join it and update the attribute.
el.classList.add('active')
el.classList.add('demo')
You would NOT need to do something like this to use data attributes, [data-example~=active][data-example~=demo] and to set it like this: if (!el.dataset.example.split(' ').includes('demo')) {
el.dataset.example += ' demo'
}
You could instead easily set two attributes and test for their presence, even if they don't have values (or you're not using them) el.dataset.active = el.dataset.demo = true
And then you can target that in CSS with [data-active][data-demo]. To remove them later is just as simple: el.dataset.active = false
And it's gone! Try to think BIG in terms of attributes, and small in terms of values. It's a lot nicer than trying to cram all of your values into just one attribute when you literally have infinite attributes available to work with!Not only do you have infinite attributes to work with, but you can
Using classes as your only way to target styles, and ignoring the other aspects of how CSS selectors can target elements is like picking up a guitar and trying to play a song, but only plucking one string. You might be making it harder on yourself to get the job done, and the result isn't any better for the effort.
EDIT: Just for kicks, have you ever considered the flexibility of what data types you can set as an attribute value other than a space separated list of strings? Try this:
// set JSON to attribute value
document.documentElement.dataset.example = JSON.stringify({one: 1, two: 2})
// get JSON from attribute value
JSON.parse(document.documentElement.dataset.example)
You can even stick a bit of JSON there as the attribute value, which can be parse/stringified by JS, is _easy_ to add or remove properties from and work with on the JS side (not requiring helper methods like classList), and is _still_ targetable by CSS once set on an element :D The possibilities are endless, the apparent limitations a lot of people butt up against are self-imposed.My main problem with this is that some people like working that way and some people don't. This leads to a mish-mash where you have two completely different places to look for where your styling might be. Since you can't specify all of your styles in this fashion, then in order for there to be one spot where the styles live, putting them in CSS files with semantic classes is the sensible default.
My other problem with it is that it encourages many DOM elements with one style each as opposed to fewer elements with more style rules. I feel like I'm swimming whenever I'm looking through the markup with an inspector.
More ideally what I'd like to see is styled-components, so the entirety of a component lives all in one code file. I don't particularly care for the use of javascript to specify literally everything on the page, from the markup to behavior to styling, but the siren song of having everything there in one place makes up for it. If you want terseness in style definition, which is the main problem this "functional" approach solves, then you can simply invoke short javascript functions.
My ideal approach though actually would lean on a text editor / IDE to keep a list of components, and opening up the markup, styling, and scripting of a component all at the same time, and just using HTML templates, SCSS, and vanilla Javascript, keeping each file unsullied by the syntax and semantics of the other languages.
I'm unconvinced that everything really needs to be Javascript, but I don't mind wandering down that rabbit hole with everybody else until the React fascination passes. It's not the worst way in the world to specify UI.
For my sites I find it useful to have a small collection of very generic classes. One common case that was annoying is how the spacing keeps changing as you move text and components around a page, and you end up fiddling with the rules all the time to adjust for how the top/bottom margins merge. No matter how "logical" it is, from a graphic design pt of view, the spacing is right when it looks right.
So I have a few very generic classes like this:
.mb-0 { margin-bottom:0; }
.mb-1 { margin-bottom:1em; }
.mb-2 { margin-bottom:2em; }
/* text */
.txt-lg { font-size:1.4em; }
.ta-r { text-align:right; }
.ws-nw { white-space:nowrap; }
These are useful for making small adjutments to the layout. That said, going all in with atomic css doesn't make sense to me.The whole reason for css is to facilitate style reuse when writing markup. In normal html pages you write a bunch of markup, chunks of that markup might represent the same "component" and so css is a great way to style those similarly using semantic class names.
If you use small components that exist in some type of template (react, vue, etc...) you can take advantage of that to facilitate your code reuse instead of a "semantic-component" css class. I think that is where utilities become valid because you still only change a components styles in one place.
Something like "const FIVE = 5" doesn't seem to capture the essence of functional programming either?
Wait, what? Who hasn't done this?
Is there anyone who's tried it for a project and still hated it? Seems like a lot of the detractors haven't actually used it yet.
One of the driving philosophies was that when one saw a CSS class, they should easily be able to find it's definition in the source. Another driving philosophy was that one should easily be able to determine what the class is doing.
This lead to classes like `u-centered`. The `u` tells me it's in the utils.less file. Classes starting with `l-` were layout classes, `t-` text classes, etc..
I had classes like this:
u-{max,min}-width-{xxs,xs,s,m,l,xl,xxl}
t-white
u-bg-red (red background)
t-h3
l-container-{xxs,xs,s,m,l,xl,xxl}
You get the picture.
(The nice thing about xl and xs is that you can keep adding x's as you need.)
I found it to be very effective. I understand the arguments that it kind of defeats the purpose of CSS, but I think CSS is pretty easy to mess up, and this give you a solid, consistent structure to work with.
Of course, I didn't follow this style 100%. There were some cases where it just made sense to use a more semantic style, but I found those case to be few and far between.
I think it makes sense in small doses but I think once you're using shell scripts to generate all these combinations you've lost the plot.
And I think that may be one of the larger points here. CSS can be simple, and using techniques like this forces it to stay that way. You have to take a step back and understand what we're trying to do as engineers. I would argue that being able to quickly understand code (e.g. the context to understand a line of code is small) should be a top priority of most software project.
But that doesn't matter because it's not an abstraction. If you have 10 HTML files and 1 CSS file, you can make a class called "warning" and have it be a background color red you've simplified those HTML files because you have less style information in the HTML.
But if you are using classes like "bg-red" or "pt-10" then you're not actually reducing the style content of your 10 HTML files. You've just renamed a style to a class. Sure you've reduced some possibilities but you've actually made the situation worse because now you have 11 files with style information. You've added new names for basic styles which adds even more complexity.
If you take that idea of reducing style possibilities to the logic extreme then you wouldn't be using classes like "bg-red" and "pt-10" anyway. You'd just do what everyone already does with CSS and abstract your styles appropriately.
Also, using Tailwind/functional CSS for items that are repeated over and over on your site like buttons, you can easily extract them to a component. Switching from bg-green to bg-yellow would be as simple as opening your SASS/LESS file for components or button components and replacing it in that one spot.
Oh, that's because running sed over all your project files, all in a set of weak typed languages is easier than changing a definition in a single place. I totally get it.
It's a little unfortunate that the use of the terms "functional" and "object-oriented" were chosen in these cases as they can easily be confused with functional vs. OO programming, when in reality CSS or any paradigm of writing CSS has nothing to do with this distinction.
There's nothing novel here. There's just a misunderstanding of how CSS works, an over-engineered solution to a non-existent problem, and then a misused name added for a veneer of sophistication.
Now add a way to hierarchically roll-up these micro-classes into semantic classes behind the scenes (Perhaps in webkit?). Compile things so you only carry-around the css micro-classes you've used, and make a flag to either deploy using the semantic or micro class method.
Best of both worlds. There are also some other mix-and-match ways of doing this. Where the real value is separating the tiny CSS adjustments you make from the business-class stuff, creating a middle tier (which this guy deploys directly)
It might make things easier. Or it could be yet another dumpster fire. I think it depends on how it's used.
Make all the "functional" classes as abstract mixins or placeholder selectors (in SASS parlance), and then use them to define your concrete semantic classes.
Which of course we already do. Maybe there's a case that the toolchain or conventions need tweaking. So it's worth the discussion in my mind. Most times you really don't realize what you need from a tool/framework until you've reinvented it, so we need folks like this doing sanity checks on where the rest of the industry is going.
When you have a "ProfileCard" class, you expect it to encapsulate the profile card without leaks, and with perfection. But that is never the case - there are so many variations of profile cards that almost everyone who uses "semantic" CSS (BEM, SMACSS etc.) end up with hundreds of tiny variation of this class, each one of them scoped to their particular container or page. Not to mention the proliferation of different shades of the same color, inconsistent typography, and ad-hoc spacings.
The right level of abstraction for user interface is the DOM+CSS; neither of them stand alone. This idea "separation of concern" has taught us to think of them in separation, and feel guilty everytime we have messy CSS that breaks that idea. But it is the idea that is wrong.
The right level of abstraction is the "component". eg: in a React component library you might have multiple Buttons, each of which is a highly reusable non-leaky abstraction. Here Functional CSS abstracts a lower granularity: design tokens/scales. It will give you consistent spacings, colors, and typography. These two in tandem is a fantastic way to look at building UIs that are consistent, reusable, and extremely easy to write and maintain.
I think the solution is using elements/components as the means of sharing styles. If you need a slightly different style you extend and modify an existing component. This can be achieved using libraries like `styled-jsx`, `styled-components`. Or hopefully as the shadow-dom spec progresses this will take care of this issue. I also think doing a way with the `scoped` attribute on the style tag was a dumb idea. As it made compartmentalization way easier.
However, I would be more inclined to use his utility classes as one layer in an ITCSS architecture and then have component styles that inherit from them, keeping them away from the markup as much as possible, while allowing to use those utility classes in the markup for quick prototyping.
This pretty much resolved my objections towards this approach. I think it makes a lot of sense with react.
A few advantages: self-documented classnames, zero dependencies, classnames are reusable across projects, removes the need for a CSS preprocessor or bundler, no need to switch between HTML and CSS file while developing, etc...
With this method of CSS it will take years to consolidate, update and redesign your application. Ask me how I know. :-)
Then Bootstrap came out, and the idea of CSS frameworks was a thing. I loved Bootstrap, but so did a lot of other people, and as a result you started seeing Bootstrap everywhere...like when you buy a car and you start seeing everyone else driving one where ever you go.
So I started trying to customize Bootstrap to make it look less like other bootstrap sites by adding custom CSS, which basically brought me back to where I started.
In practice it has been much, MUCH easier to work with CSS frameworks that use utility classes, because it makes customization easier. I do think there needs to be an intermediate layer where it's easy to define semantic classes as composites of utility classes. I would think this should be possible in the days of Less, Sass, and precompiled web sites.
For instance, one component was a cropping viewport that had to be a set height and width. There really isn't any solution for that other than adding a very specific utility class, or creating a semantic class.
Personally, Tachyons still provides me tremendous value even though I sometimes have to write custom classes. I'm also often surprised to find that something that I thought would need a custom class, could be done with Tachyons when I dug a bit deeper.
For building things out and prototyping it was amazing though.
On the plus side our css file was so tiny.
>You never have to deal with one instance of a thing needing a slightly different style than the other instances, which screws up your reusable classes.
...what I found was that just as often, I'd need a new Atomic class different in a subtle way from existing ones, and this was annoying to implement because
a) it expands the kludge-dictionary of short class names you have to memorize, but often in a way that's too situational for anyone to actually memorize it, meaning the next time someone runs into the same problem they will re-invent the same solution rather than reread the entire list of Atomic classes to see if one exists, and
b) the whole point of Atomic is that I shouldn't have to be writing CSS, and I was, all the time.
For web apps, I contend that modularity ought to be the goal for HTML, JS, and CSS. In the project I'm working on now, each widget/component has its HTML, JS, and CSS together in a single folder. When a widget/component is first loaded, its CSS is added to the DOM. Each component has a unique parent class name, and all its markup and styles are nested under it.
Having cross-cutting styles that are re-used throughout the app sounds decidedly un-modular. Why not re-use components/widgets instead?
I remember once looking up on the proposed alternatives to CSS. One was basically a lisp, or at least the syntax, as far as I recall it. Think of what you could do with that!
However the problem now is that the problem CSS intended to solve can only be considered in terms of CSS itself. I'm curious what other approaches could be taken if we worked entirely from a clean slate. Would it involve changing the DOM? Would it require a separate language? Who knows...
CSS works great for websites but not so much for full-blown apps, where you're programming with a totally different mindset than what the web originally anticipated.
.m10 may be fine for desktop but not for mobile.
Then you’ll have media queries which define .m10 as margin: 5px or something, which is nuts.
You could go for unspecified .mSmall etc, but in real life, things tend to be more specific and messier, in my experience.
CSS has come a long way since CSS Zen Garden.
With CSS grid and flex, you can create components with less markup and small amounts of CSS.
The example on the tailwind site https://tailwindcss.com/docs/what-is-tailwind/ just looks like a steep learning curve to me. I could write that same component with much less HTML and just a few lines of responsive css.
If it's popeprly designed functional CSS would be exaclty what it actually looks like - garbage.
Like include "materialShadow(3)" for a hovering button, but when you want to build a special card thingy you include "card", which than includes the shadow already.
I agree that Cascading part of the CSS is very troubling, but I don't think functional CSS solves it in an elegant way. Actually I think it's hardly readable and confusing :(
As of the argument that you don't need to write CSS properties anymore, I would suggest using a plugin like Emmet [1].
I mean, the ONE BEST THING about CSS is its ability to promote consistent styling across a site by creating REUSABLE, NAMED styles that are SEMANTIC and applying them consistently.
Let us run through the author's claimed list of advantages:
> You don't have to write any CSS of your own (which, to me, is fantastic)
This one is an obvious troll.
> You can likely build things faster (obviously non-scientific, but anecdotally I've seen many people confirm this)
The combination of "likely" and "obviously non-scientific" undermines this claim (and rightly so) in the middle of making it.
> You don't ever have to think about naming things
Again, I presume this is a troll. Naming things is hard if you care about having meaningful names. If you don't care, then naming is trivial. This approach eliminates meaningful names so it is hardly a benefit.
> You can tell what something looks like by just reading the markup for it
That one is an actual advantage, and makes me wonder slightly what's going on.
> You don't ever have to worry that changing the styles for one thing will break something else (which may make visual regression testing irrelevant)
Another obvious troll. If you never reuse anything, you'll never have to worry about a change breaking anything else. Also true if you never change anything. Also completely meaningless.
> You never have to deal with one instance of a thing needing a slightly different style than the other instances, which screws up your reusable classes.
True enough... if you never reuse anything, then you never need to worry about the impacts of reuse.
> Your CSS always stays the same size rather than expanding over time
Well, sure! If you move all of the intent out of the CSS file and into longer and more complex style attributes, then the CSS file itself will get shorter (while the length of the CSS file PLUS the style attributes will get longer).
> It's easy to un-apply a style by just removing the class (as opposed to the traditional cascade where you typically have to override, adding even more CSS)
This isn't even well-considered. Using a fixed set of single-visual-effect-not-semantic-intent styles will have no effect on the complexity of cascading. Choosing to apply styles only to individual elements and eschew the use of cascading WILL avoid all the complexity of cascading, but the choice to do that is independent.
> Rendering speed performance is supposedly improved (though I have seen no proof of this)
There is no reason this would be true, and the author isn't even claiming it.
After reading it through, I am beginning to seriously doubt that this was intended as satire. In which case the author is very, VERY wrong. I continue to hope that I am simply missing the joke.
It sounds like the author wants Functional CSS to be the Ultimate CSS Solution™, when in most cases, you can write better CSS and/or stick to a design system and/or plan out and manage your components better.
Web-Components may help someday, but so long as component properties are effectively strings, and hard to pass in from the outside, same for events, it makes it harder to manage discreetly.
It causes repetition that would be avoided by defining a single CSS class (this can and probably should be done inside in the file defining the component), and also prevents making appearance changes outside of the component (e.g. in non-component JavaScript or with a CSS-changing browser extension).
If you want to obfuscate the semantics, then "minimized" class names are a better solution.
If you don't care about repetition, then inline styles are just as good, and actually better since you can for instance use any of the 2^24 sRGB colors.
None of the "downsides" listed in the document are reasonable arguments:
> Inline styles don't respect media queries, which basically rules out responsive design
"Utility classes" also don't, unless you define one for each possible media query and style (that's > 2^16 possible widths, > 2^16 possible heights, > 2^8 attributes...).
> Inline styles aren't limited to pre-defined options, meaning you can still end up with 90 different shades of blue
That's a downside, and also CSS has built-in color names.
> Inline styles cause specificity issues, since they trump separate stylesheets.
Use !important.
> Inline styles don't support print-specific styles.
True I suppose, but nobody cares about printing webpages nowadays, and those who are meticulous enough to care probably aren't choosing between inline styles and utility classes since they are both bad approaches.
> Inline styles can't address pseudo-elements (such as ::before and ::after)
You can just put the content in the HTML itself if you are explicitly specifying the appearance.
> Inline styles can't apply to multiple elements. Utility classes can define .bg-blue once and have it apply to many things, which leads to shorter markup and quicker rendering speed.
class="bg-blue" has to be repeated just as much as the equivalent background style...
> Inline styles are a pain to type. Compare class="f-sm bg-blue" to style="font-size: 10px; background-color: #0000ff;".
You should use IDEs with autocomplete, and then they are going to be easier to type, and most importantly developers already know them and can thus easily read and write them without consulting any documentation or CSS file.
You can't be serious can you? Css has what around 150 color names? That is jut not good enough for any serious work.
> Use !important.
Please don't use !important, avoid it as much as possible. It just compounds the issue.
> class="bg-blue" has to be repeated just as much as the equivalent background style
But the definition of what shade of blue we're using is in only one place. Forget bg-blue and think of theme-blue, theme-blue-highlight, theme-blue-mid and so on. A professional design needs vocabulary.
> You should use IDEs with autocomplete
Do these IDEs help with reading and interpretation?
Atomic CSS
What's time complexity for each operation(by human)?
Read: O(sigh)
Insert: O(1)
Delete: O(n)
Update: O(n)
Pre-BEM era CSS
What's time complexity for each operation(by human)?
Read: kinda O(1)
Insert: O(1)
Delete: O(1) without garbage collect (unused css)
Update: kinda O(n^n)
That's a quick thought, maybe your operations are more arbitrary.
Probably when someone introduces new css framework/technique, showing some kind of complexity measurement (if possible) would be good idea?
The semantic approach forces you to generalize your HTML up front and leads to over-engineering styles. Plus JS component libraries make refactoring across a project a lot simpler.
Referencing the OP’s example in short:
#m-5 {
margin: 20px;
}
.card {
@extend #m-5;
/* custom styles */
}
Edit: formattingKeep your CSS as absolutely shallow, declarative, and "noun-based" as possible. Stay away from utility classes and "adjective-based" classes. Preferably everything should be within it's own component (React/Vue/Web component/etc.).
After reading https://adamwathan.me/css-utility-classes-and-separation-of-... i might use it even more!
Composing .profile-card out of these could be a functional approach, but you're just writing @style via @class.
Today, CSS Grid and Flexbox are easier and more powerful than any framework, and aside from bleeding-edge features the major browsers have converged.
> You don't have to write any CSS of your own (which, to me, is fantastic)
This applies to any CSS or UI framework.
> You can likely build things faster (obviously non-scientific, but anecdotally I've seen many people confirm this)
Yes, this is anecdotal and debatable. At the end of the day, you still have to read the documentation of this specific CSS framework.
> You don't ever have to think about naming things
I don't think developers that are creating anything don't ever have to think about naming things. If you're creating something, you have to name it. But yes, you don't have to add that name to your CSS class.
> You can tell what something looks like by just reading the markup for it
You could also tell what something looks like by just reading the CSS for it.
> You don't ever have to worry that changing the styles for one thing will break something else (which may make visual regression testing irrelevant)
There's a couple other approaches to this like style localization/isolation that the author called "ton of crazy randomly-generated class names". As opposed to the ton of single-purpose utility class names, which is more sane? You could also write stricter CSS selectors (like BEM or your own).
> You never have to deal with one instance of a thing needing a slightly different style than the other instances, which screws up your reusable classes.
Sure, as long as if you stick to a framework. If you're building a one-off with no collaboration with other people, then this is easier to pull off with an off-the-shelf CSS/UI framework.
> Your CSS always stays the same size rather than expanding over time
Okay!
> It's easy to un-apply a style by just removing the class (as opposed to the traditional cascade where you typically have to override, adding even more CSS)
You could isolate styles that are prone to removal into a single class with regular CSS too. Hate to be the nerd to say this, but the "Cascade" in CSS is what makes it such a versatile interface styling engine.
> Rendering speed performance is supposedly improved (though I have seen no proof of this)
Once again, anecdotal.
————
Sounds like the author is allergic to reading/writing CSS and wants the markup to be heavily coupled with styling. Also sounds like having a strict framework makes their developer experience happy, which is applicable to any well-designed design system.
There's nothing wrong with any specific CSS methodology or framework, and there's a time and place for every single one of them.
I think I would prefer vanilla CSS with strict rules for one-offs before using something like this, though.
e.g.
> .mb-1 {margin-bottom: 1rem}
> .text-center {text-align: center;}
> .flex {display:flex;}
But why would you give up the templating win of CSS?
Make a standard button class.
When you want it to have a different (standard) margin, use a utility class on it.
Then when the next PM wants this button to be blue, you make another utility class and end up editing HTML. It's better to just think entirely in terms of components that are independent of any external framework or guideline, which are only responsible for themselves. Everything on your page is a concrete implementation of an abstract component, and in that implementation you can customize all you want. Otherwise you end up with a massive dependency graph between components of various "utility classes" rather than a completely flat hierarchy of components which handle their own dependencies.
So you're suggestion that when the PM wants this button to be blue, you make another component for that button? You haven't changed the problem, or the amount of work, you are just using a different layer to implement it.
Changing the layer you're implementing on is the whole point. It's about maintainability and keeping things encapsulated.
Now when someone comes back to look at this button a year later, they're not left wondering why this usage of "Button" is colored blue, and tracking down the utility class. They will know that it's an instance of "BlueButton" and can just edit the component directly.
Now, more than likely the component isn't called BlueButton and the CSS class isn't called "blue" but rather both would have a name more semantically appropriate.