How I write CSS

, 10 minutes to read, 250 views

There appears to be an endless discussion about how to properly write CSS. Utility first, mobile first, should use SCSS and maybe Tailwind CSS or don’t use it1.

As you can see, there are countless people who have opinions, sometimes forceful opinions, on the topic. And yes, I would like to now tag my opinion as well. Well, my opinion is a bit special in that I have a strong opinion on not having a fixed opinion. More on that later.

It all started off with this toot that I saw in my feed2:

📝 What Is Utility-First CSS?

heydonworks.com/article/what-i

(this was going to be a video, but it got pretty long, plus I think there's a small chance this could appear high in organic search if shared enough)

HeydonWorks What is Utility-First CSS?

This was probably one of the first times I saw something properly critical of the Tailwind CSS approach, which was quite a refreshing piece to read.

A brief history of my CSS usage

Like anyone playing around with the web, I used some very basic inline styles for the most part when I started messing around with writing websites. I quickly learned to put my styles in a separate CSS file, as this was meant to have various advantages, including only having to load it once across all the pages of a website. And while I was experimenting around with various CSS stuff, I quickly realised that this was not necessarily something I was good at. And by that I don’t mean writing CSS, I consider myself to be excellent at that, but rather I was not very good at styling in general3.

At some point, there was talk of building websites in such a way that they can be used comfortably on any size window (it wasn’t really yet about mobile, but it was going in this direction). I learned of an Open-Source project at Twitter4 that was called Bootstrap. Bootstrap was something else, it was easy to use, looked beautifully professional, and it was written in something strange called less. This is what allowed Bootstrap to be used effortlessly and smartly. One could download some themes or write one themselves. And often it was just adapting a few variables in the variables.less file, and you had some custom colours, borders and maybe even shadows.

I used Bootstrap everywhere; I even designed a quite nice-looking website for my family:

I know that censoring something on a screenshot makes it so much more enticing. Please be advised that in the interest of data minimisation, I removed some words in this screenshot. Nothing too interesting, just trying to enhance privacy a little. I’m not even sure if Gaussian blur is not mathematically reversible. With enough effort, you can still find this page somewhere.

And while Bootstrap was the start (for me as well as so many other people using it everywhere) it was always a bit heavy5 and required some JavaScript to be included as well. And while it had a tool to remove styles you didn’t need, it had a size problem, and it had a further problem: Most websites kind of looked the same, yes even if you had a custom theme.

From there I tried various CSS frameworks: Foundation, which I never really got on with as it seemed very similar to Bootstrap, Bulma which I remember using once but then everything being pastel colours and very rounded and finally Pure.css which I used to use for my personal website6.

But slowly I moved away from all this and I started to use the cool new kid on the block.

Material Design was the shit

At some point around 2016 everything became Material Design. It just looked so modern, and it was also super familiar from android devices. Everything was now a card, the font was always Roboto. Those were the good times. And that was the first time I actually built my own blog with my own template:

That was the original German blog on the domain oli.fyi. And yes, I was already using Hugo, in fact, Hugo 0.47 which allowed for Hugo Pipes as well as the asset minification. Those were the days. It was also the start for me where I was moving away from static pages.

Moving away from static pages resulted, at least that was the case for me, in the world of React. React was a fresh breeze and it was just so cool. It was mostly all client side, and it also made it straightforward to load a random component from NPM. Need a chart, there’s a NPM package for that. Want to add some accordion, yup there’s a package for that as well. Maps? Yup! Markdown? Of course! Date picker? Why on god’s green earth would you write that yourself?

Adding stuff was just super easy and for the most part in early React development nobody really cared about the bundle size of your JavaScript. After all, we have fast internet and fast devices7. And for React, I was using mostly MUI since it had the same Material Design, but it was using React under the hood. This was fine, and it worked for a long time.

Of course, every once in a while something was not doable with the MUI component, and then it was a pain in the ass. Either one had to customise the components through MUI’s customisation system (which I never really got the hang off) or do something yourself with something like styled-components. That was it, and it worked great for a while. The challenges I faced was not really finding a fitting graphing library and more often than not having to do something manually myself, and that was not why I wanted to use such a “framework”8.

Utility First CSS and Tailwind CSS

After starting to write more and more CSS again by hand, often using SCSS to make it a bit more streamlined and also often using the excellent CSS Modules the splitting of design as well as the repetition of the styles was more moved to my React components and less in the structure of the HTML. And so I was basically forced to arrive at Tailwind CSS at some point.

Tailwind was fast and easy to use and produced (thanks to PurgeCSS or now the Just-in-Time Mode) small files. I always liked to get the small and optimised files. If I’m not using a style, I also don’t want to send it to the client’s browser, easy enough. I however, never really felt comfortable with the class names in the code. Not really what is the reason for this, but in my head HTML code should be, at least to the extent possible, be human-readable. In my mind, this applies only to HTML and less to CSS and as such, I use class names, SCSS and the @apply directive from Tailwind CSS. Is this how Tailwind CSS is supposed to be used? No, not really, but I can do what I want and this gives me a bit of flexibility in just adding some vanilla CSS if I ever need9.

Tailwind CSS has a big following online, and every so often it feels a bit evangelical to me. It feels like there is only one right way to use Tailwind CSS and if you are not using this way, people get angry at you on the internet10. Tero Piirainen goes as far as to call the marketing for tailwind misinformation. And also the author of the above toot has a critical piece on utility first CSS. I don’t have that strong of opinions here, but while I think Tailwind CSS is pretty cool, it is not a one-solution-for-all-problems.

If it’s stupid, and it works, it’s not stupid

At the end of the day, I don’t think there is a right or wrong way to style on your website (I mean maybe inline a hole bunch of CSS WordPress-plugins-style is not the best idea). What is essential is that it somehow works. And if you are in a team, you do something that works for the entire team.

When I do something myself, I use Tailwind CSS and make liberal use of the @apply directive. So why not vanilla CSS? I find that it is just a bit quicker using Tailwind CSS, the colours are a bit more pretty and there are some very useful features such as prose. Finally, I also think that all the flex box magic is just much easier and more legible using Tailwind CSS.

But for example at work11, where we often have templates from professional designers, we mostly use component-based repetition, and we then just write SCSS. It works well for us as a team and given how the designers provide us the data, writing plenty of components that are (in the best case) reusable is probably the best way for our team to work. Is it perfect? No, in fact, we frequently have the discussion about code duplication vs having components that try to do too many things. Regularly we also struggle to abstract styles and functionality, but eventually, it works, and we get stuff done.

So after all, there really is no wrong way to do CSS, and that makes all of them right.

Also, CSS doesn’t need to be boring or nice or well designed, you can go crazy if you’d like: wombat.monster.


  1. It’s a bit crazy to me how many of these technically focused blogs that I have been reading as part of this research use medium as a blogging platform. I mean I get it a bit, it looks beautiful needing to do anything, but I mean c’mon. All the blogs look the same and for some reason it keeps asking me to accept some strange cookies and also become a member. What is that? And why is a simple blog post about 5 MB. We can all do better. ↩︎

  2. Yes, I love me some mastodon embeds, and I will not change my opinion on that. And I still think static embeds are a great invention and probably the coolest thing I learned recently. ↩︎

  3. I was looking for examples from my earliest websites, unfortunately they have all been long gone by now. I did find my old blog in the Wayback Machine from 2013, unfortunately that was using a WordPress theme and therefore is not really my early experiments with CSS, and it actually looks beautiful, which is not indicative of the websites I wrote around that time. ↩︎

  4. Sometimes I remiss a little back to the time when Twitter was a cool company, doing cool open-source projects for everyone. ↩︎

  5. Because it was a bit heavy we used to use a content delivery network, so we were embedding some strange code such as https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css and we didn’t even use subresource integrity. 😱 ↩︎

  6. Unfortunately this website is also not online anymore, and the domain now redirects to my business card website↩︎

  7. This is sarcasm, of course it matters how many bytes we transmit. If you didn’t detect the sarcasm, I have failed↩︎

  8. Is MUI really a framework? Not in the sense of a Typescript framework, it basically a set of matching React components and some utilities for styling. ↩︎

  9. Sometimes, when I have stupid, often hacky, ideas I need to use vanilla CSS, as it cannot be done in Tailwind CSS. An example of this is the logo of this blog, this would not be possible with Tailwind CSS and is not even possible using stable browser APIs (oh well). ↩︎

  10. Yes, I’m also doing it wrong and break all kind of rules listed on this page. Fight me! ↩︎

  11. I can of course not talk about client projects at work, but you should be able to find some examples of what we have worked on if you try hard enough. ↩︎

Tags: SCSS, Style, Tailwind CSS, Technical