CSS: Selector Variables
Published on Feb 7, 2008 (updated Jun 18, 2022), filed under development (feed). (Share this on Mastodon or Bluesky?)
This post is partially outdated.
Complex projects suffer from higher cost of selector changes, and long sequences of simple selectors do impact the understandability and efficiency of style sheets. One solution could be selector variables or “synonyms,” a concept I proposed to the CSS Working Group yesterday, again if you want as Carmelo Capinpin did suggest something similar in 2006.
The ongoing discussion brought up a few questions concerning definition and behavior (David Baron) and use cases (Elika Etemad) and revealed issues concerning the specification and implementation of these variables.
Here the proposal again:
The basic idea is to syntactically allow definitions like
E = F;
…so that rules matching
E
would matchF
as well (and the other way around), while variable (or synonym) declarations could probably be located at the beginning of a style sheet or within a certain @-rule.A more advanced step [for] even more benefits is to allow selector grouping and a specific placeholder syntax as well, as in
E = F, G; @H = I;
…where
@H
wouldn’t mean a “regular” selector but a “placeholder” only viable in style sheets and requiring a “regular” selector equivalent.While current selector grouping
[…]covers some use cases [for] these variables, there are a few specific benefits to them (omitting “when used right” and cutting examples):
Improved maintainability and “refactorability”:
Currently, the wish
[…]for ID and class name changes can only be addressed when both markup and style sheets are changed. Selector variables could not only offer faster changes and better maintainability by allowing “change CSS now, HTML later” cases, they could also mean a helpful precaution, for example, when IDs/classes are changed “anywhere” but authors are not or can not be sure if [there are any leftovers], or when they need to tolerate delayed changes on partner sites using the same CSS files. (Talking complex projects, this is.)Example:
.old = .new;
Improved style sheet clarity:
Extensive use of contextual selectors and/or long ID and class names usually resulting in less clear style sheets might be avoided by selector variables.
Example:
@foo = #navigation li a;
Improved CSS efficiency:
Not talking about possible compression tools, style sheet size might easily be decreased by “compressing” long selectors through variables—without style sheets necessarily getting less readable or understandable.
Elika’s question for use cases and the problems the suggestion tries to solve lead me to additional reasoning:
The main problem the suggestion attempts to solve is the cost of selector changes. Currently, selector changes (above all referring to ID and class names) require changes in both HTML and CSS. There are cases, however, where especially complex sites cannot guarantee all HTML to be changed, at least not in a timely fashion, while in these cases, selector grouping reduces maintainability (after all, the selectors in question should be changed, not extended) and bears a larger risk of getting overlooked later. Thus, improvements are either delayed or even dropped, and both cost and risk of changes are relatively high.
Selector variables could offer low-cost, instant changes without any risk of formatting and “compatibility” problems, via
.old = .new;
or@foo = .old, .new;
, for example.Another use case I see is the effect the (by all means desirable) way to use sequences of simple selectors has on CSS understandability and efficiency, meaning that “contextual selectors” are elegant but tend to be longer [and therefore] less understandable than simple selectors (referring to more complex style sheets again).
Example (HTML 4):
<ul id="nav"> <li><strong>Home</strong> <li><a href="/exit">Exit</a> <!-- … --> </ul>
#nav strong {}
Assuming that the default
li
/strong
element styling is not desired and the author wants to style indicators of “active” pages differently, the selector#nav strong
appears to be an appropriate choice. However, a simple selector like#on
would be shorter[, though it’s] not elegant HTML:<ul id="nav"> <li><strong id="on">Home</strong> <li><a href="/exit">Exit</a> <!-- … --> </ul>
#on {}
Although there are even less characters used in the second example, it [shouldn’t] mean too much abstraction to project that on cases where the selector in question is used more than once, and that exactly is the other problem: How can style sheets get more compact while at the same time preventing unneeded HTML changes and staying readable?
As for the example above and given that our selector is used five times, selector variables/placeholders could make
@on = #nav strong; /* user agent just replacing ”@on” by ”#nav-strong” */ @on {} @on, .foo {} @on, .bar {} @on, .baz {} @on, .qux {}
out of
#nav strong {} #nav strong, .foo {} #nav strong, .bar {} #nav strong, .baz {} #nav strong, .qux {}
I’m looking forward to feedback from the Working Group, though it won’t be easy for me to “talk spec” and address all issues. See specific problems like the handling of @foo, E = .bar, #baz; E@foo {}
or test cases; things will boil down to articulating sound arguments.
In case my English lets me down: Can you challenge this, or support the case?
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.)