CSS, DRY, and Code Optimization
Published on OctĀ 9, 2014 (updated FebĀ 5, 2024), filed under development, css, maintainability, optimization (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 been working as a technical lead and engineering manager for companies youāve never heard of and companies you use every day, 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.)