I was just chatting with Eric Meyer the other day and I remembered an Eric Meyer story from my formative years. I wrote a blog post about CSS specificity, and Eric took the time to point out the misleading nature of it (I remember scurrying to update it). What was so misleading? The way I was portraying specificity as a base-10 number system.
Say you select an element with ul.nav
. I insinuated in the post that the specificity of that selector was 0011 (eleven, essentially), which is a number in a base-10 system. So I was saying tags = 0, classes = 10, IDs = 100, and a style attribute = 1000. If specificity was calculated in a base-10 number system like that, a selector like ul.nav.nav.nav.nav.nav.nav.nav.nav.nav.nav.nav
(11 class names) would have a specificity of 0111, which would be the same as ul#nav.top
. That’s not true. The reality is that it would be (0, 0, 11, 1) vs. (0, 1, 0, 1) with the latter easily winning.
That comma-separated syntax like I just used solves two problems:
- It doesn’t insinuate a base-10 number system (or any number system)
- It has a distinct and readable look
I like the (X, X, X, X) look. I could see limiting it to (X, X, X) since a style attribute isn’t exactly a selector and usually isn’t talked about in the same kind of conversations. The parens make it more clear to me, but I could also see a X-X-X (dash-separated) syntax that wouldn’t need them, or a (X / X / X) syntax that probably would benefit from the parens.
Selectors Level 3 uses dashes briefly. Level 2 used both dashes and commas in different places.
Anyway, apparently I get the bug to mention this every half-decade or so.
so like semver it doesn’t overflow to the more meaningful part, it absolutely makes sense
You could use a dot-notation and then the idea of a bigger number being more specific would hold true.
1.0.1 vs. 0.11.1
Agree. Similar to the version number.
Cool walk down memory lane thanks for the CSS specificity fun! I do suggest swapping This is a very useful tool for generally weighing the specificity of a given selector. The model will as you point out fail if we calculate using a fixed 10 rather than the ‘broad’ base in CSS specificity algorithm. One factor that I believe has muddied the waters even more than the concept of a broad algorithm for folks is how the !important declaration factors in to weight calculations. This has caused over-reliance on that declaration to resolve specificity conflicts which, when resolved in the CSS with a more specific selector, the !important declaration can be used for the purpose which it was intended: To ensure my User Style Sheet rules actually do override the Author rules provided, usually because I have an #A11Y concern and am applying my personal styles out of need. Otherwise, the elegance of the Cascade ends up broken. Some of users still want to employ baked in clean CSS approaches of scale. Thank you for getting me enthusiastic about specificity again, for some reason a long lived enchantment born of my own DOH! Moments from the bad ol days
Great article. I’ve always thought that writing the specificity without a separator was ambiguous and could cause trouble. Thanks for putting this out there.
I also agree that we can remove inline styles from the calculation–for brevity–as we do with the !important keyword, since both negate everything else. And most of the time they aren’t (read: shouldn’t) be used. Plus, (X, X, X) is simply more readable than (X, X, X, X, X).
BTW–
ul#nav.top
has a specificity of (0, 1, 1, 1), not “(0, 1, 0, 1).”