Evolving CSS
I recently built this site out from scratch. On this sort of rare occasion where I’m staring down a greenfield design opportunity, I try to re-examine my practices around CSS, how to organize it, and what tooling to use with it.
I’ve always seen CSS as fundamentally unsustainable. The story is always the same: it starts out perfectly fine as site and stylesheets are small, then growth and time take their inevitable toll, and suddenly development becomes CSS property whack-a-mole. Styles cascade in invisible and unintuitive ways, so making a change somewhere can lead to a regression somewhere else that might go unnoticed for days. Many ideas have been proposed over the years to address this problem – e.g. requiring explicit styling “modules” on every single element – but I’ve still never seen one I really liked. The vast majority of properties on the internet still just brute force their way through knowing that all style breakages will be found given enough eyeballs.
I sure didn’t solve that problem, but in my case that’s okay. This site’s going to stay small, and the same goes for its companion stylesheet, so I should always be able to keep it all in my head at once. That said, I did try a few tweaks to my standard practices now that new CSS features and improvements are widely available:
No pseudo-CSS language: I originally became addicted to the succinctness of SASS. Not having to include curly braces or semicolons was a godsend for speed, correctness, and readability. Access to variables, mixins, and other advanced features was very helpful. And although I still prefer SASS’ syntax, for the first time in many years I ditched it in favor of vanilla CSS. More features are available in plain CSS nowadays, and the overhead of a pre-processor isn’t worth it anymore.
One file: I’m keeping everything in a single file partitioned into sections by big comment blocks. This helps me avoid having to remember where things are (I’d always end up with a
main.sass
or the like that contained miscellaneous styling), and simplify my build pipeline.CSS variables: One of the big reasons I could now ditch SASS is that variables are now widely available (CanIUse estimates ~95%). In fact they’re better than SASS variables ever were because it’s easy to tweak their values for
@media
annotations used in responsive design. This works beautifully::root { --entry_vertical_margin: 80px; --paragraph_vertical_margin: 25px; } @media handheld, only screen and (max-width: 767px), only screen and (max-device-width: 767px) { :root { --entry_vertical_margin: 60px; --paragraph_vertical_margin: 18px; } }
No reset: I’d always use a CSS reset file to ensure perfectly consistent styling across browsers, but it always came with the downsides of having an extra CSS file around, and having to rebuild styling on every element from scratch. This time, I’m trusting that basic styling between browsers is close enough, and jettisoned the reset.
No minification/post-processor: I got rid any post-processor or attempt at minification. CloudFront respects
Accept-Encoding
, most browsers will ask for gzip, and CSS compresses well. Even with no compression, the file is smaller than the smallest image the site serves anyway, so it’s a drop in the bucket.Go straight to flex: Flexbox isn’t perfect, but allows you to do so many things that used to be nigh-impossible in CSS so much more easily. The best-known example being centering an element horizontally and vertically inside its parent container – something that CSS has traditionally made incredibly difficult. It’s been widely available (99%) for some time now so I use it extensively and shamelessly.
Fewer browser prefixes: Many browsers will read traditionally exotic CSS features without their specific prefix nowadays, so I stopped using them in many cases: e.g.
animation
,border-radius
,transition
. Stylesheets becomes shorter and easier to read.
One thing I’d love to have is a good linter that would tell me things like if I’d forgotten a semi-colon, duplicated a style block, or was using a prefix I didn’t have to. It seems there’s a decent command line linter available in the Node ecosystem, but there’s no way I’m bringing NPM into my development loop, which currently takes on the order of 100s of ms end-to-end. So for the time being, I’ll be living without.
As software matures, it’s very common for it to evolve more layers of abstraction, arguably making the results more powerful, but wide side effects like expanding complexity, greater performance overhead, and making it more difficult to understand. I’m quite happy with this latest CSS iteration because it’s a rare example of the opposite – more than a few ungainly components and modules were cut loose, and the overall effect is a simpler system that’s just as effective.
September 4, 2020 (4 years ago) by