CSS, DRY, and Code Optimization
Published on October 9, 2014 (⻠February 5, 2024), filed under Development (RSS feed for all categories).
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 frontend engineering leader and tech author/publisher. Iâve worked as a technical lead for companies like Google and as an engineering manager for companies like Miro, Iâm a contributor to several web standards, 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. (Please be critical, interpret charitably, and give feedback.)
Comments (Closed)
-
On October 9, 2014, 15:41 CEST, Gunnar Bittersmann said:
A CSS preprocessor like Sass might come to rescue.
For your example: From Sass code%placeholder1 { declaration1 } %placeholder2 { declaration2 } %placeholder3 { declaration3 } %placeholder45 { declaration4; declaration5 } %placeholder6 { declaration6 } feature1 { @extend %placeholder1; @extend %placeholder2; @extend %placeholder3; } feature2 { @extend %placeholder45; @extend %placeholder1; } feature3 { @extend %placeholder6; @extend %placeholder2; }
the desired CSS would be generated:
feature1, feature2 { declaration1 } feature2, feature3 { declaration2 } feature1 { declaration3 } feature2 { declaration4; declaration5 } feature3 { declaration6 }
(In the real world, the placeholder rulesets would usually contain more than one declaration, as indicated for %placeholder45.)
Cf. slides 76/77 in my presentation CSS preprocessors for the best of both worlds at From the Front 2014. (PDF, 10 MB)
Jens, youâll love slides 43/44. đ
-
On October 9, 2014, 15:50 CEST, Jens Oliver Meiert said:
I need to look at this again so just a rather instinctive reactionâwhy would you want WET source files, and is that really simpler to author?
-
On October 9, 2014, 17:26 CEST, Gunnar Bittersmann said:
The Sass code is indeed WET in the sense that ‘@extend %placeholder#â appear multiple times for different selectors.
But it can be DRY regarding the values. For example:
%placeholder1 { property1: value-foo }
For changing the value from value-foo to value-bar thereâs one single point of change, regardless how many feature# extend that placeholder. -
On October 10, 2014, 12:30 CEST, jaison justus said:
I use BEM + SASS to achieve modularity and usability. Still figuring out to improve.
-
On October 12, 2014, 15:57 CEST, Jens Oliver Meiert said:
I think weâre right back at the beginning, Gunnar. Note that I donât want preprocessor users to defend themselves. I want more focus on CSS optimization, whether âsourceâ or production files, and I believe Iâve reasonably laid out why that is important.
-
On October 14, 2014, 16:05 CEST, Drew Bell said:
Doesnât this spread the styles for a given element all over the place, though? Iâm much more likely to be working on âcontainers for form alertsâ or âfilepicker listsâ than I am âthings that have auto marginsâ, right? I donât trust myself to remember where all the styles for a given module live in the stylesheet, and hold them in my head at once.
-
On October 16, 2014, 11:31 CEST, Kay said:
Jens,
thanks for the article!Iâm full of questions:
Where do you exactly see the benefit in repeating your ‘featuresâ over and over again and only write as few declarations as possible?
By looking into the CSS of this site Iâm spotting countless h1-selectors where you could have only one which would be a lot easier to locate in the stylesheet and easier to maintain (exspecially when youâre working in teams instead just for yourself..).
I really donât understand the part where youâre overwriting h1âs important-declarations with other important-declarations.
My opinion is donât ever use the !important declaration because it really quickly becomes a pain to maintain them.Your point in your article is to avoid declaration-repetions but isnât selector-repetition even worse?
-
On October 16, 2014, 12:41 CEST, Jens Oliver Meiert said:
Hi Kayâas described in the post, declarations are usually longer, and so normalizing them means bigger code savings. Additionally, going by declarations does in turn make maintenance easier, for itâs simple to update, say, color values and such. As a matter of fact, the need for constants/variables may completely disappearâthatâs how powerful the method is. Also as described đ
As for
!important
, I donât think itâs helpful to add here as itâs unrelated to DRY in CSS. And so my reasons to use!important
are unrelated to using declarations once. (Exceptions prove the rule, as there may be needs due to changes in the cascade.) Please note that thereâs nothing wrong with!important
; itâs a legitimate part of the cascade and can be a very effective tool. Thatâs, so I found, a healthier mindset than the outright ban we find in other places. -
On October 16, 2014, 15:11 CEST, Kay said:
Thanks for the quick reply, Jens!
Iâll consider your suggestions in my next project.
Itâs always good to hear other attitudes then my own đ
Read More
Maybe of interest to you, too:
- Next: Google and HTML/CSS Code Quality
- Previous: On Declaration Sorting in CSS
- More under Development
- More from 2014
- Most popular posts
Looking for a way to comment? Comments have been disabled, unfortunately.
Get a good look at web development? Try WebGlossary.infoâand The Web Development Glossary 3K. With explanations and definitions for thousands of terms of web development, web design, and related fields, building on Wikipedia as well as MDN Web Docs. Available at Apple Books, Kobo, Google Play Books, and Leanpub.