Harry Nicholls recently wrote all about simplifying styles with functional CSS and you should definitely check it out. In short, functional CSS is another name for atomic CSS or using “helper” or “utility” classes that would just handle padding
or margin
, background-color
or color
, for example.
Harry completely adores the use of adding multiple classes like this to an element:
So what I’m trying to advocate here is taking advantage of the work that others have done in building functional CSS libraries. They’re built on solid foundations in design, people have spent many hours thinking about how these libraries should be built, and what the most useful classes will be.
And it’s not just the classes that are useful, but the fundamental design principles behind Tachyons.
This makes a ton of sense to me. However, Chris notes that he hasn’t heard much about the downsides of a functional/atomic CSS approach:
What happens with big redesigns? Is it about the same, time- and difficulty-wise, or do you spend more time tearing down all those classes? What happens when you need a style that isn’t available? Write your own? Or does that ruin the spirit of all this and put you in dangerous territory? How intense can all the class names get? I can think of areas I’ve styled that have three or more media queries that dramatically re-style an element. Putting all that information in HTML seems like it could get awfully messy. Is consistency harder or easier?
This also makes a ton of sense to me, but here’s the thing: I’m a big fan of both methods and even combine them in the same projects.
Before you get mad, hear me out
At Gusto, the company I work for today, I’ve been trying to design a system that uses both methods because I honestly believe that they can live in harmony with one another. Each solve very different use cases for writing CSS.
Here’s an example: let’s imagine we’re working in a big ol’ React web app and our designer has handed off a page design where a paragraph and a button need more spacing beneath them. Our code looks like this:
<p>Item 1 description goes here</p>
<Button>Checkout item</Button>
This is just the sort of problem for functional CSS to tackle. At Gusto, we would do something like this:
<div class="margin-bottom-20px">
<p>Item 1 description goes here</p>
<button>Checkout item</button>
</div>
In other words, we use functional classes to make layout adjustments that might be specific to a particular feature that we’re working on. However! That Button
component is made up of a regular ol’ CSS file. In btn.scss
, we have code like this which is then imported into our btn.jsx
component:
.btn {
padding: 10px 15px;
margin: 0 15px 10px;
// rest of the styles go here
}
I think making brand new CSS files for custom components is way easier than trying to make these components out of a ton of classes like margin-*
, padding-*
, etc. Although, we could be using functional styles in our btn.jsx
component instead like this:
const Button = ({ onClick, className, children }) => {
return (
<button
className='padding-top-10px padding-bottom-10px padding-left-15px padding-right-15px margin-bottom-none margin-right-15px margin-left-15px margin-bottom-10px ${className}')}
onClick={onClick}
>
{children}
</button>
);
};
This isn’t a realistic example because we’re only dealing with two properties and we’d probably want to be styling this button’s background color, text color, hover states, etc. And, yes, I know these class names are a little convoluted but I think my point still stands even if you combine vertical and horizontal classes together.
So I reckon that we solve the following three issues with functional CSS by writing our custom styles in a separate CSS file for this particular instance:
- Readability
- Managing property dependencies
- Avoiding the painful fact that visual design doesn’t like math
As you can see in the earlier code example, it’s pretty difficult to read and immediately see which classes have been applied to the button. More classes means more difficulty to scan.
Secondly, a lot of CSS property/value pairs are written in relation to one another. Say, for example, position: relative
and position: absolute
. In our stylesheets, I want to be able to see these dependencies and I believe it’s harder to do that with functional CSS. CSS often depends on other bits of CSS and it’s important to see those connections with comments or groupings of properties/values.
And, finally, visual design is an issue. A lot of visual design requires imperfect numbers that don’t properly scale. With a functional CSS system, you’ll probably want a system of base 10, or base 8, where each value is based on that scale. But when you’re aligning items together visually, you may need to do so in a way that it won’t align to those values. This is called optical adjustment and it’s because our brains are, well, super weird. What makes sense mathematically often doesn’t visually. So, in this case, we’d need to add more bottom padding to the button to make the text feel like it’s positioned in the center. With a functional CSS approach it’s harder to do stuff like that neatly, at least in my experience.
In those cases where you need to balance readability, dependencies, and optical adjustments, writing regular CSS in a regular old-fashioned stylesheet is still my favorite thing in the world. But functional CSS still solves a ton of other problems very eloquently.
For example, what we’re trying to prevent with functional classes at Gusto is creating tons of stylesheets that do a ton of very specific or custom stuff. Going back to that earlier example with the margin beneath those two elements for a second:
<div className='margin-bottom-20px'>
<p>Item 1 description goes here</p>
<Button>Checkout item</Button>
</div>
In the past our teams might have written something like this instead:
<div className='cool-feature-description-wrapper'>
<p>Item 1 description goes here</p>
<button>Checkout item</button>
</div>
A new CSS file called cool_feature_description_wrapper.scss
would need to be created in our application like so:
.cool-feature-description-wrapper {
margin-bottom: 20px;
}
I would argue that styles like this make our code harder to understand, harder to read, and encourages diversions from our library of components. By replacing this with a class from our library of functional classes, it’s suddenly much easier to read, and to change in the future. It also solves a custom solution for our particular needs without forking our library of styles.
So, I haven’t read much about balancing both approaches this way, although I assume someone has covered this in depth already. I truly believe that a combination of these two methods is much more useful than trying to solve all problems with a single bag of tricks.
I know, right? Nuanced opinions are the worst.
I’m working on an internal project right now where I’m combining functional and regular CSS. For example, I’ll use regular CSS for an object or element that I know will be global on every page of the site, or rendered much the same way whenever it’s added to page (e.g., the primary navigation or a component like a button). Since this is an internal project with established branding, etc., I feel comfortable “locking in” the styles this way for those elements.
But I’ll frequently use functional CSS as a way to fine-tune elements, or when I need to have much more page-specific elements and patterns (e.g., how a gallery grid looks on page A as opposed to page B).
I’ll admit that it’s sometimes a gray area, and there have been times when I’ve gone back and forth on whether to rely more heavily on functional CSS or regular CSS, but so far, it seems to be working pretty well.
Magic word is “page-specific elements and patterns”. In my opinion CSS organization it should be like that.
Having a CSS class of “margin-bottom-20px” (and other similar things) reads, to me, like inline styles for someone who finds the “style” attribute toxic, just saying…
“And, yes, I know these class names are a little convoluted”
I still prefer using Harry Roberts’ ITCCS architecture. This way you can work on a scalable setup whilsts using both functional and regular CSS at the same time with the ‘components’ and ‘utilities’ layer. Best of both worlds I think. Gives you a ton of flexibility, because there is never one solution to all client/codebase problems ;)
I wrestled with this exact problem!
My main difference is that I liked functional CSS for styles that won’t change, but adding variations for interaction states, media queries, and other variations can become a problem. I wrote about it on CodePen if you’re interested.
HI!, Thanks for share!, you could use classnames for improve reading
Have you checked out Tailwind—it’s utility first, but it encourages creating components once you have a pattern.
https://tailwindcss.com/
I am completely against the use of utility classes, but I do use them.
To me, styling has a meaning, and it’s what should be visible in the code: class names should reflect what they are here for, not what they precisely do.
In your example, I would probably have a classname like .my-component__spacing. So it would tell that this “element” intends to do spacing, but it doesn’t tell exactly what spacing. Then in the stylesheet, I would whether have a “magic number” for this spacing or include an already existing spacing class of 10 or any other round number.
The outcome is: a utility class used behind something that integrates with a meaningful “object-oriented” naming.
Does that make nay sense?
We’ve been using the exact same approach for year and are quite happy with it. Combining classical BEM approach with what we call utility classes is like having the best of both worlds. We are usually introducing utility classes where otherwise the number of modifiers on a component would explode (e.g. spacing, semantic text colors, text alignment, etc)
Functional CSS is for people who don’t want to write CSS.
The biggest drawback in this approach is responsive Design. These days there are massive changes in behaviour and appearance of the elements of a site which were a huge pain until pretty recently.
To me it looks like functional css feels like it doesn’t know the history of webdesign and neglegts the pain that was inline styling.
No, I disagree. I have been writing CSS for 15+ years. I love the language. But I have almost never reskinned an application by just retooling the CSS. The few times I have done that, it’s been gross. There are limitations.
Almost always, it’s been an HTML – AND – CSS adjustment, making them both sync again. The idea that you should write and rewrite CSS and markup hooks seems outdated to me. CSS is a finite thing. Markup will never be. Let’s economize where we can by writing less CSS. Compose with classes. Add component classes and special flowers when they’re needed.
Utility classes can be made responsive (ie. .flex, .md–flex, .lg–flex). Arguably, this is a much more human-readable method of approaching styling, and especially layout. I can see what’s intended – the class .component-x is completely opaque.
These aren’t inline styles – besides, the real issue with that is specificity. And before someone injects semantics into the argument, the whole idea of semantics with classes is weird. We have data attributes, roles, elements, etc; those are for semantics. CSS is for layout and styling. Let it do that.
I combine these two all the time. I guess I’m not reading enough about CSS though, I’ve never heard of Functional CSS or Atomic CSS until now. I always just referred to the classes themselves, calling them utility CSS. I’ve lots of others do this too.
I agree there is little point to being a CSS (or any type of code style) “purist” — each of these approaches has its use-case, and why not combine them?
I am curious about the class names like “margin-bottom-20px”. Why have the class at all? Not being snarky — I’m honestly curious why that would be an improvement over a “style” attribute. Wouldn’t it just be extra bytes (the class definition, plus the long class attribute)? And what if you decide all the “spacing” in your layout should actually be 18px instead of 20px?
Components are for my idealistic future self and utility classes are for my realistic future self. Utility classes make things easier when working with a big team. It speeds up development time and helps with consistency. Components are still at the core, but utility classes are so helpful. If everyone edited CSS perfectly, components alone might be fine, but that’s rarely the case in practice.
Bem your components and position them in your layout with utill classes.
My approach is this:
If it can be built with utilities-only, build it with utlities.
When patterns emerge, start abstracting them. Depending on the stack this might be components or BEM classes that reuse the utilities (Tailwind’s @apply rule is great for that).
I only put context-neutral styles into a components. E.g. I try hard to avoid adding margins, alignments or dimensions into a component that might change depending on context.
For example a
card
component will abstract all styles for design what’s happending inside the component. But depending on the context where it’s being used, it might require a different spacing outside, so I’ll mix in the right utilities depending on the context in which it’s used: it might look like<div class="c-card mx-4">
and<div class="c-card mx-2">
in another, where less pouter spacing is desired (mx is Tailwind’s name for horizontal margins). Another simple example would be variations in text sizes.c-button
holds basic styles to define the look of a button. If I need a larger button I simply add the according utility classc-button text-xl
and thus avoid landing in BEM modifier hell (and if the button’s margins were set usingem
units it will automatically scale nicely with the text size).This is exactly what I’m doing as well. It works nicely, right?!
I think I’ve stolen all the best bits from Harry Roberts’ InuitCSS, applied some additional flexbox, and then pinched a bunch of Tailwind class names.
To me, utilities first is very unreadable and increases cognitive load. As a developer, I’ll run into classes like this: “p-1, m-2, d-this, d-that”. My brain now has to run some operations, to de-code that code and I end up spending more time in the content area of the app then in the styles area of the app.
That said, I tend to use a mixture of both, but prefer to use very really lightweight utility classes for two reasons: (1) to keep the HTML as clean as possible (especially for more complex, business-logic heavy applications), and (2) because I like using SASS files as the main control center and “interface” for managing, iterating on, and scaling an application.
Here’s an example of a mixture of semantic and utility that I’ve found is an elegant balance of both:
Our in-house team are using a combination of Functional CSS and Sass. Instead of writing the “bg-black” as class in HTML, we wrote it in a Sass mixin.
Check out the documentation here: https://hrsetyono.github.io/edje/
We’ve seen faster development time and better understanding between team member.