Found myself in agreement up until the concept of "semantic CSS class names". If you want semantic markup, then CSS is absolutely not the place to implement it IMHO.
We did this for a project a few years ago and it was alright. In the end we decided against doing it again purely because the DOM became so extreme with one-rule classes that it became a nightmare to read the templates. So much noise.
For building things out and prototyping it was amazing though.
This seems to misunderstand the basics of why we have CSS in the first place, to separate "how something appears" from "what something is", and suggests to mix the two.
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.
You can introduce implicit coupling in any app (i.e. in a non-CSS programming language). It's bad practice in both cases.
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.
This. In addition, it means you have to edit multiple things to change how something looks.
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.
> If .login-box is now going to be larger but green, you'd normally just edit the CSS to change that.
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.
I think you misread my comment. By 'normally' I mean using regular 'CSS controls how something looks' HTML, and not using visual class names (that this author calls 'functional CSS').
I quoted the wrong sentence, I meant to reply to the "you'd have to edit the HTML" aspect. Functional CSS lets you wrap up composite styles in various ways, similar to abstracting a function in normal programming, so you don't necessarily have to do this. You can though, and it's often simpler to do so.
In my experience, more often than not, the opposite is happening. The designer wants the same widget to have a slightly different style in different places. Then you either give it some additional class for context or use helper classes. Benefits of either approach seem to be moot. Reusability suffers in any case.
I've found this is (usually) solved with soft skills. I just talk to the designer and explain we have all these very similar components already and it will help with the visual consistency if we follow an existing convention OR update the existing convention to use the new style (giving them the option to choose let's them stay in control of the design). They are usually very understanding as they don't always consider these things.
It's also rarely a surprise that if you ask "why did you special case this particular [button/widget]?" to some designers the answer turns out to be "I didn't have a good template and just redrew it" or "I don't know, I was just freehanding that because I was in the flow".
Most of the "a lot to love" points are also hit by BEM/SMACSS. In regard to this point:
>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.
Tailwind takes care of this. You just need to define your spacings, colors, typography, and a few other details like borders and shadows, and all the classes you'll need are all there. You can use PurgeCSS to trim down the final CSS size to just the classes you use.
Maybe it's not a reference to functional programming but to that other definition of "function", you know, the one used by everybody except programmers.
My experience with functional CSS was skepticism followed by delight. Reading BEM style actually makes me more skeptical now. A class of "Button Button__Primary" tells me much less about the styles of that button than a string of functional CSS classes would.
Which is useful, but that's the extent of the depth of information I'm getting. I like that functional CSS lets me see "how something is" over "what something is."
Isn't this the same as regular programming? When you have a function called updateUser(), that doesn't tell you every single thing about its implementation, nor do we expect it to.
When the customer asks me to change the background of primary buttons from green to yellow and the background of nonprimary buttons to red, while changing other green backgrounds to a green-brown gradient, classes like "Button Button__Primary" tell me much more than classes like "bg-green".
Your customers speak a different language than most of mine. The requests are more like "I need the green buttons to be yellow now!" It's easy to find bg-green on buttons and just find/replace with bg-yellow.
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.
> It's easy to find bg-green on buttons and just find/replace with bg-yellow.
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.
Which is why you have a styleguide. Open your browser, open your well crafted styleguide. Here is what our "Button" looks like, here is it again when its got "Button_Primary" on it. Do you need a new type of Button? Author it in the styleguide... now go use it everywhere and be happy. I might be wrong, but in my experience a separation of concerns is the only way a large project stays healthy.
You shouldn't need to know what the exact visual style of the button is. That's not important. You have a button, it's the primary button. What else do you need to know when coding your HTML?
We did this at my last job, but inevitably ended up with a mix of half functional CSS and half component CSS.
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:
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.
> 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.
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.
Both "solutions" don't address the problem of repeated class names, they just help repeating them in a correct but not less obscene way. Bloated markup cannot be defended.
I usually don't want people to be able to create infinite variations of things because of a lack of consistency.
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’m about to start writing a very simple html page ( think search panel + result table underneath) after having stayed out of html for a few years. What are the current best practices regarding css tools and framework that could make my life easier ?
HTML + CSS, pure and simple. Don't overthink. Frameworks like bootstrap were useful back when they started: column layout (and other popular patterns) were hard to achieve, and each browser (and version) had their own quirks to work around.
Today, CSS Grid and Flexbox are easier and more powerful than any framework, and aside from bleeding-edge features the major browsers have converged.
Functional CSS is a terrific approach. Tailwind in particular is exemplary.
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.
so i'm on board with your central concern here. my issue with functional css is that your markup has no semantics. you can't just look at it and know what things are by their names. ie,
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.
From the other perspective, I know what "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light" will look like and I can immediately change it. I have no idea what "profile-card" does, and if it's ultimately something I don't like I have to go through the whole asset pipeline to change it.
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.
There's another active post right now [1] where Tailwind's creator has been addressing these understandable initial reactions.
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'm sold on building up your UI through the composition of utility classes.
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.
"... your markup has no semantics. you can't just look at it and know what things are, by their names."
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?
> but it's orthogonal to the things that make Tailwind and functional css great
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.
> Absent this approach, in web projects of nearly any size, the CSS inevitably grows and becomes increasingly difficult to maintain.
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:
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.
Yeah. I was reading this thinking "If only we had some way of abstractly creating CSS!"
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.
I tried using Tachyons for a project and it really broke down when I needed to make really custom components.
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.
I think the point is that Tachyons should be good for 90/95% of the styling you want to apply to the site. I think the creator would be the first to say that if you need something specific which Tachyons can't do you should do that but it doesn't make Tachyons redundant.
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.
What about theming/branding so that you can make your enterprise web-app fit in with each of your clients other web-apps?
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.
It's all about tradeoffs, there are no silver bullets. If your class name is like profile-card then it could be simpler... until it's not. Because it turns out that one of your client profile-card needs to behave slightly differently on hover or whatever. In theory, profile-card is a great idea, in practice it can be a headache
What I'm saying is you have files client-alice.css and client-bob.css, and you define different profile-card:hover rules in each. But with functional css you have nothing to hang your rules on.
Even if you only have one client - do you really want to manually hunt down all profile-card instances and update the styling anytime you need to change the styling?
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 :)
It's unclear to me the problem you are addressing. Searching for places to make amendments is an important consideration when naming something. I would have thought that class names like "profile-card" would be easier to search for than "m-5 p-5 text-gray-light bg-gray-darker border border-gray-light". Especially if you have some page elements which may look the same now but are functionally different and could look different in the future. How would you find one and not the other?
Is that the problem you were addressing or did you have something different in mind?
I was commenting on the original proposal, even in the single-client context. So, we're talking about the same problem - I just obviously wasn't very clear about it :)
So, yes, semantic names matter, and functional names are a bad idea in the long run, because they shatter maintainability.
I used this technique in my previous startup. I even had shell scripts that generated my LESS files.
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.
Seems like a waste of time when you can just do style="background: red;". You're not adding anything to CSS you're just renaming and enumerating all the style attributes and values.
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.
There's a big difference between class="u-bg-red" and style="background: red;". The big difference being that the class make it so that it is first-class application idea.
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.
"u-bg-red" vs. "backround:red" is just the same thing aliased. If you were to introduce an actual concept like "warning" or "error" that was red that would be different.
You are correct from one point of view. But, the point I was making was that the class definitions for bg color can be contained within a single file in your application. Using `style` is completely different in that anything is possible. This is a big deal, as cutting down on possibilities/simplifying is a very important process in software engineering.
> But, the point I was making was that the class definitions for bg color can be contained within a single file in your application.
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.
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.
One thing I think CSS frameworks got wrong is mixing layout with style. At the time, maybe it was justified due to lack of layout options. But today, especially with grid, but even flexbox, layout can entirely be done by the framework's consumer, and should probably not be done by the framework itself, which should focus probably mostly on style. Unless of course it's a layout framework, but grid is so flexible and easy to work with that you probably don't need a layout framework. I'll just leave this here https://learncssgrid.com/
> One thing I think CSS frameworks got wrong is mixing layout with style.
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.
> 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.
The big difference between this and "background: #333" is that in the later case it could also be "background: #334" or "background: #435". The functional framework approach forces a minimal amount of consistency.
This stuff never scales. No one can remember the class names, no one want's to search through the examples and style guides for a project, no one want's to standardise naming of their own hacks etc and so you start of with good intentions and end up with a lot of duplication and a whole lot of shit.
CSS is an expressive markup. You shouldn't try to turn it into programming.
> This stuff never scales. No one can remember class names
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.
No, I'm saying anyone that tries to standardise CSS with a universal theory is wasting theirs and their companies time and resources.
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.
I'm not particularly good at identifying satire, but this is a joke, right?
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.
Same thoughts as you, and it looks like we both went through the benefits line-by-line with a comment in this thread!
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.
As a frontend developer of 15-20 years now I've been pretty dumbfounded and unconvinced by any arguments for this style of css, I think it's especially hard for frontend developers of such duration because this is effectively the first ever style of css you write, and then you were force fed xhtml, semantic web and then later responsive became the "Told you so!" of the methodology.
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.
I'm a frontend developer of about 15 years as well and I think functional css makes a lot of sense. My biggest argument for it is not having to name every thing. You know how many times I've had to think of a name for a random container that exists simply to align some crap? Then if you need another wrapper or something for that for some reason? It eliminates the name game (whenever you want it to).
The everydollar web app used to have a lot of utility classes and it was a nightmare to work on. We've spent a lot of engineering hours cleaning that up. I suppose if you were completely strict about only using utility classes you might get a little farther, but I still wouldn't recommend utility classes. The best idea I've seen is utility SCSS mixins applied behind the scenes to BEM classes or locally scoped css.
> I think that separation of concerns (i.e., the whole idea that the markup should be completely independent from the styling) is something that has been burned into our brains because of the history of CSS (trying to get people away from using tables, sites like CSS Zen Garden, etc.)
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.
Functional CSS changes a mistaken way of thinking about CSS classes: as a unit of visual abstraction.
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.
245 comments
[ 3.3 ms ] story [ 279 ms ] threadFor building things out and prototyping it was amazing though.
On the plus side our css file was so tiny.
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.
>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.
Something like "const FIVE = 5" doesn't seem to capture the essence of functional programming either?
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.
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:
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...
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...
Today, CSS Grid and Flexbox are easier and more powerful than any framework, and aside from bleeding-edge features the major browsers have converged.
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.
versus:
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.
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){
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.
[1] https://news.ycombinator.com/item?id=18084013
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:
This becomes even easier in SASS: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.
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.
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.
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.
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.
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.
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.
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.
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.
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.