CSS, DRY, and Code Optimization
Published on Oct 9, 2014 (updated Feb 5, 2024), filed under development (feed). (Share this on Mastodon or Bluesky?)
This and many other posts are also available as a pretty, well-behaved ebook: On Web Development. If the optimization of CSS is of particular import to you, I’ve collected several concepts in a brief book: CSS Optimization Basics.
When I explained the problems with type sorting in CSS I realized that the type sorter’s motivation was a particular problem, not just mere preference. It was something more fundamental, something that has caused us web developers more headache. The underlying problem is that people repeat themselves too often in CSS—or repeat the wrong code too often, respectively.
Now, not repeating ourselves in code makes for an important maintainability principle. My own guide on maintainability is lacking in this regard, but if we pull up common definitions, we find that “don’t repeat yourself (DRY) is a principle of software development aimed at reducing repetition of information of all kinds” as it “usually makes large software systems easier to maintain” (Wikipedia), or that “duplication can lead to maintenance nightmares, poor factoring, and logical contradictions” so that “every piece of knowledge must have a single, unambiguous, authoritative representation within a system” (Cunningham & Cunningham). I’ll assume that it’s clear why maintainability is important and how DRY contributes to it.
The Natural Way of Writing CSS
What happens in our style sheets is that we’re too seldom making an effort to avoid repetition. The natural tendency is, if at all, to only involuntarily avoid repetitions of selectors, simply because of the way we code. That way consists of focusing on features, and features are represented by selectors and groups of selectors.
Let’s look at an example, although I’ll abstract it a little to find a balance that gives just enough understanding before flooding ourselves with unnecessary specifics. When we start with a project and its style sheet we tend to work a bit like the following:
feature1 {
declaration1
declaration2
declaration3
}
…
feature2 {
declaration4
declaration5
declaration1
}
…
feature3 {
declaration6
declaration2
}
(“featuren” stands for the selectors for our features, and “declarationn” for different declarations, unless carrying the same number.)
That is the basic approach, which doesn’t change, in principle, when adding more selectors and declarations. I claim that everyone works like this. It’s how we all write our CSS code, initially.
Naturally, then, through our focus on features we tend to avoid repetition of selectors. Not entirely: We tend to. But that’s not helping us.
For one, what is happening is that the bigger the style sheet, the more entropy and repetition there are. The order of selectors, declarations, rules, and sections gets more and more chaotic, and there are more and more duplicates both in terms of selectors and declarations (and possibly even rules). The web developer who hasn’t observed this should more carefully check his style sheets, and I say this kindly for I know the pressure we’re sometimes under.
For another, the seemingly fortunate circumstance of not repeating ourselves as much with our selectors is not just more of a coincidence owed to how we work, but also not as helpful because, as they’re supposed to, selectors are usually shorter than declarations. That is, any savings here in terms of avoided repetition get eaten up by the repetition we observe when it comes to our declarations. We get a glimpse at that in the code example.
The Optimized Way of Writing CSS
The improved way of writing CSS does not, in my book, mean changing the way we naturally code. It rather consists in focusing on post-optimization that avoids repetition. Surprisingly—or not! that’s why Google paid me a very good salary—, the solution to avoiding the bulk of repetition in CSS is a method I promoted and polished in 2007/2008: to use every declaration just once. (Yet, the first mention on this site didn’t get that much attention, while the Google version didn’t find open ears.)
Using every declaration just once appears to be much the most effective way of applying DRY to CSS. To get to the typically significant savings (20–40%), a bit of manual labor is involved, however. How this process looks like I had already shared in said posts on this site and at Google, so I’m not going to repeat myself, either.
Code Optimization, the Web Developer’s Stepchild
I’m sometimes a bit of a lazy writer who readily assumes that everyone can follow his accent and his way to write prose. Here perhaps, too, as I’ll for the moment take it that everyone understands why we need DRY in CSS, how DRY in CSS is work, how that work rests on declarations, not selectors, and that that work requires manual labor for it’s very difficult to automate.
But now I want to extend this point to my general concern that we don’t focus enough on CSS optimization. And I think DRY is a great example of this not just because it’s neglected much of the time, not just because it, when omitted, encourages type sorting, but because it, again forgotten, has also led us into the constants and mixins rabbit hole.
What happened here was that web developers found themselves writing a lot of code, as per the natural approach, to then demand to simplify CSS code through constants and mixins. That must now appear as a knee-jerk reaction, for three reasons:
From a technology standpoint, using constants and mixins was already possible through languages like PHP. Bert Bos explored this issue in a nice article about variables back then, to which I could add only little.
From a problem standpoint, using declarations just once already greatly reduced repetition and complexity to a diminishing need for constants.
(As for the so criticized sorting of declarations by type, using declarations only once reduces the average number of declarations per rule to about two, down from ten or more type sorters use in examples. That is the realization I mentioned in the beginning: the type sorter’s root problem is likely the natural, non-optimized way of writing CSS.)
From a problem-solving standpoint, looking at reducing complexity through variables was skipping another important step, which is trying to avoid that complexity (which may have led right to DRY).
Although I recognize a need for constants and mixins, I believe the whole no-DRY-but-cry-massively-for-variables incident is a great example of how we neglect CSS optimization. We don’t look closely enough at how we can write better CSS, how we get more out of it, and how we can avoid the problems we run into before calling in heavy CSS Working Group artillery.
Not as lazy as suggested, this must do for the moment. The most important thing to take out of this post, please, is to minimize repetition in style sheets—perhaps through using declarations just once—, to focus more on CSS optimization, and to consider that avoiding problems is also a way of solving them.
Update (July 3, 2017)
In the meantime I’ve taken and studied additional data around repetition in CSS (notably the repetition of declarations) and shared more thoughts on DRY CSS and the idea of using declarations just once: 70% Repetition in Style Sheets: Data on How We Fail at CSS Optimization.
About Me
I’m Jens (long: Jens Oliver Meiert), and I’m a web developer, manager, and author. I’ve worked as a technical lead and engineering manager for small and large enterprises, I’m an occasional contributor to web standards (like HTML, CSS, WCAG), and I write and review books for O’Reilly and Frontend Dogma.
I love trying things, not only in web development and engineering management, but also in other areas like philosophy. Here on meiert.com I share some of my experiences and views. (I value you being critical, interpreting charitably, and giving feedback.)