My work, though, is building products, not arguing on the internet, or showing off. My approach to CSS is both boring and, in a certain light, ludicrous. Here it goes:
Never(ish) to write new CSS. The application should grow, but the stylesheet shouldn’t. If you find yourself writing CSS, it’s because you need something very custom and particular to this specific application.
Just use a CSS file, and the most vanilla user-facing setup possible. With a small or medium-sized stylesheet, you don’t have to think about the size of the styles because they’re always a tiny percentage of the total application size. Observable’s full stylesheet is 20kb. We don’t slice and dice it, we just point to it with an old-fashioned link tag.
Fall back to inline style properties for one-off styling. Regular refactoring rules apply here: whenever we write inline styles, we do a second pass to see if they can’t be represented by classes, and then if the same inline style pops up in multiple places, it’s considered for inclusion as a class.
Use native CSS features as much as possible. I’ve never used Sass or Less, and always stuck to what works in browsers. Luckily in 2019 what works in browsers is a frankly incredible set of primitives. CSS Variables, for example, work in all our target browsers, so we ship them directly and then are able to refer to the variables in style properties, to keep everything consistent.
CSS frameworks should provide you with standardized values for things like colors, dimensions, and fonts. They should also provide you with the benefits of classes - pseudo-selectors and media queries. Beyond that, you shouldn’t expect them to make your website responsive or look pretty.
This all brings me to tachyons, the framework of choice. Admittedly I didn’t arrive there directly, but there’s a line of succession from Mapbox’s base.css to assembly, and then basscss, which I used on a number of side projects. They’re all within the same general school of thought: one that emphasizes tiny, composable classes. So, in my case the basic ideas for this were given to me by Young Hahn and some of the designers at Mapbox.
See, a lot of frameworks have high-level concepts baked in: you might write
<button class=btn type=button>Button</button>
To show a button on screen. Whereas, to take a live example from Observable, a button looks like:
<button class="ph3 pv2 f6 fw6 white bg-blue hover-bg-dark-blue pointer br2 bn" type="button">Edit collection</button>
Linebreaks added for readability.
You might recoil in horror. That’s fine - this approach might not be for everyone. Don’t @ me.
But it grows on you, and then you can’t imagine doing it any other way.
Why? Well, for one thing, Observable is an application, and it’s one with some relatively subtle style challenges. A few buttons have to be responsive and lose some padding when the viewport is small. Others have to be links, but look like buttons.
Thanks to the extreme granularity of classes in Tachyons, there’s never a case where I need to write a new class to describe a new variation of a button, or for that matter, almost anything else.
And when we want to change something globally, we can do so with precision: tweaking the color of
dark-blue on the site tweaks it everywhere.
There are disadvantages to Tachyons.
You’re only going to be fast using it if you can memorize the class name structure, and, well, there are lots of class names. It’s another thing to learn.
The defaults aren’t going to make your site beautiful. We use a private fork of tachyons-custom that makes some changes, like slightly different colors and tweaked font stacks. This isn’t purely a disadvantage, though, because if Tachyons had distinctive and beautiful defaults, you’d also have to swap them to avoid looking cookie-cutter.
Should you use Tachyons? Or CSS-in-JS? Who am I to tell you. This approach works for me and my coworkers tolerate it. CSS, like all programming seems a little nuts, but it’s not all bad. Arguably, with things like grid, flexbox, and variables, CSS is better than it’s ever been before.
And another obligatory note that every problem area is different. This blog doesn’t use Tachyons (or React, or much of anything). It’s a blog, not an application, and it needs very few styles and the design changes very slowly. If I was building websites that were product brochures or something else, I’d also make different technology choices based on what fit the problem.
But I build applications, and in my experience, this approach works well for them. Just be prepared to remember some classes.