David Baron's Weblog

:-moz-any() selector grouping

Saturday, 2010-04-24, 10:13 -0700

Last night I landed support for :-moz-any() selector grouping. This allows providing alternatives between combinators, rather than having to repeat the entire selector for once piece that's different. For example, it allowed replacing this rule in our user-agent style sheet:

/* 3 deep (or more) unordered lists use a square */
ol ol ul,     ol ul ul,     ol menu ul,     ol dir ul,
ol ol menu,   ol ul menu,   ol menu menu,   ol dir menu,
ol ol dir,    ol ul dir,    ol menu dir,    ol dir dir,
ul ol ul,     ul ul ul,     ul menu ul,     ul dir ul,
ul ol menu,   ul ul menu,   ul menu menu,   ul dir menu,
ul ol dir,    ul ul dir,    ul menu dir,    ul dir dir,
menu ol ul,   menu ul ul,   menu menu ul,   menu dir ul,
menu ol menu, menu ul menu, menu menu menu, menu dir menu,
menu ol dir,  menu ul dir,  menu menu dir,  menu dir dir,
dir ol ul,    dir ul ul,    dir menu ul,    dir dir ul,
dir ol menu,  dir ul menu,  dir menu menu,  dir dir menu,
dir ol dir,   dir ul dir,   dir menu dir,   dir dir dir {
  list-style-type: square;
}

with this one:

/* 3 deep (or more) unordered lists use a square */
:-moz-any(ol, ul, menu, dir) :-moz-any(ol, ul, menu, dir) ul,
:-moz-any(ol, ul, menu, dir) :-moz-any(ol, ul, menu, dir) menu,
:-moz-any(ol, ul, menu, dir) :-moz-any(ol, ul, menu, dir) dir {
  list-style-type: square;
}

In theory, I could even have used:

/* 3 deep (or more) unordered lists use a square */
:-moz-any(ol, ul, menu, dir) :-moz-any(ol, ul, menu, dir) :-moz-any(ul, menu, dir) {
  list-style-type: square;
}

but this would have been slower since it no longer falls into the tag bucket. (If :-moz-any() turns out to be popular, we could add extra code so it's just as fast, but I haven't done so yet.)

:-moz-any() is allowed to contain selectors with multiple simple selectors (using the css3-selectors definition of simple selectors, not the CSS 2.1 definition), but it is not allowed to contain combinators or pseudo-elements. So you can write :-moz-any(p.warning.new, p.error, div#topnotice) or :-moz-any(:link, :visited).external:-moz-any(:active, :focus), but you can't put "div p" or "div > p or ":first-letter" inside :-moz-any().

This has a -moz- prefix for two reasons. First, it's just a proposal, and hasn't made its way into any specification. And second, it isn't quite ready for prime-time, though, since it doesn't yet handle specificity correctly.