At Halfstack Conf in May I gave a presentation on what I think responsive design should be about in 2020 and what it will be about going forward: responding not just to static device properties like width and height but also to user preferences like preferring dark mode or reduced motion. The recording of it […]
Making functional CSS work for me
For a long time I’ve wanted to like functional CSS systems like Tachyons and Tailwind. The concepts behind them are really appealing to me. Using short names for CSS property:values saves a lot of typing (hello Emmet, nice to see you again!), but more importantly by limiting the amount of design choices you can make, the implementation time will go down tremendously.
Adding a bunch of utility classes to all HTML elements never really sat well with me though, for a couple of reasons.
- There’s a ton of repetition, putting the burden of consistency on me. My CSS tends to be mostly “generic” styling, and I am not good at consistency.
- Doing any “interactive” things like hovers required some (to me) hacky classes that don’t work well unless you fully control your list of classes via JS.
- The ordering in a class attribute is meaningless, and by doing styling only with these classes, you obscure which style take precedence.
Trying out Tailwind
It felt more like I was missing something rather than functional CSS not working though. So I decided to develop a website using Tailwind. I ran into problems relating to the issues I mentioned above (such as, the
no-underline class always takes precedence over the
underline class), as well as some missing features. I was not having a good time.
To be fair, the missing features are available in plugins to keep the core file size down. They are not official plugins though, so if you want to have transition classes, for example, it’s your task to decide on the merits of three different plugins, each a couple dozen lines of CSS. That felt like such a waste of time that in the end, I added my own transition utility classes. I would’ve preferred a kitchen-sink approach, since there are tools like PurgeCSS that will automatically clean your CSS to just the applied styles.
After this exercise I wasn’t convinced functional CSS actually solved a problem for me. It felt more like creating a bunch more. Yes I was a little faster at some things, but I didn’t like having to give up the cascade, I didn’t like how having so many classes on each element looked and I didn’t like how it removed one of CSS’ superpowers: easy consistency.
Generic versus specific
The problem I found was indeed with me: I tend to write a little generic CSS for elements that would be applied everywhere, and then write specific CSS for specific elements. Functional CSS is great for the specific elements, but it has no solution for generic styling.
Applying utility classes is great and simple for specific components, but if 90% of your styling is done with a few element selectors then foregoing that for adding the same classes to the same elements everywhere is putting the cart before the horse.
Turns out, Tailwind has a solution for this with PostCSS (which I use). You can use the @apply syntax in your own CSS blocks to add utility class styling to your own CSS selectors. This lets me write my generic styling for repeated elements (paragraphs, headings etc) in my CSS, cleaning up my HTML and immediately getting rid of the repetition. So I can write this:
@apply text-grey-darker pb-4;
And happily use my classless but styled paragraphs everywhere. Any exceptions like different padding or alignment can then be solved with functional classes.
This ‘hybrid’ approach helped me work around issues I encountered and made using Tailwind a lot more enjoyable. I’m not sure if it’s how you’re supposed to work with functional CSS, but it’s how it works for me.