Firefox 4: -moz-any() selector grouping

This is a re-post from David Baron’s blog. This feature has landed in Mozilla Central (trunk) and only available with a Firefox Nightly Build for the time being.

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.

Note: This will be extremely valuable in an HTML5 context when it comes to sections and headings. Since section, article, aside, and nav can be nested, doing something like styling all h1 elements at different depths could be extremely complex.

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
section h1, article h1, aside h1, nav h1 {
  font-size: 25px;
}
/* Level 2 */
section section h1, section article h1, section aside h1, section nav h1,
article section h1, article article h1, article aside h1, article nav h1,
aside section h1, aside article h1, aside aside h1, aside nav h1,
nav section h1, nav article h1, nav aside h1, nav nav h1, {
  font-size: 20px;
}
/* Level 3 */
/* ... don't even think about it*/

With -moz-any():

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
-moz-any(section, article, aside, nav) h1 {
  font-size: 25px;
}
/* Level 2 */
-moz-any(section, article, aside, nav)
-moz-any(section, article, aside, nav) h1 {
  font-size: 20px;
}
/* Level 3 */
-moz-any(section, article, aside, nav)
-moz-any(section, article, aside, nav)
-moz-any(section, article, aside, nav) h1 {
  font-size: 15px;
}

About Paul Rouget

Paul is a Firefox developer.

More articles by Paul Rouget…


27 comments

  1. Warren Parsons

    Wonderful idea! I really hope this takes off and other browser vendors pick it up down the road.

    IE? Maybe in version 13… Maybe.

    May 18th, 2010 at 10:07

  2. JD

    I think there should be a feature to define a set of colors like:

    DEFINE(primaryColor:#CC3333);
    DEFINE(secondaryColor:#333333);

    .class{color:primaryColor;background:secondaryColor;}

    May 18th, 2010 at 10:51

    1. Magne Andersson

      That’s been brought up many times before, under the name “CSS Variables”. It was decided, though, that this should not be part of the CSS standard, at least not CSS3 and below.

      (Presumably it’s because CSS is supposed to be a very easy and simple language, which is good, but still limits you in some areas.)

      May 18th, 2010 at 14:35

  3. Magne Andersson

    It’s great indeed, and probably speeds up rendering a bit, but the one I have the highest expectations for is the -moz-cycle()/cycle() expression (https://bugzilla.mozilla.org/show_bug.cgi?id=363250) ;-)

    May 18th, 2010 at 12:38

  4. Andy L

    Thank you for moz-any(), Mozilla!

    I hope Google Chrome / WebKit will implement it soon as well so I can use it in my webapp. (For IE I’ll be using Chrome Frame.)

    Magne Andersson:
    cycle() will be useful indeed! +1.

    May 18th, 2010 at 14:29

  5. Barryvan

    I agree with Warren — it’d be great to see this functionality spread to the other browsers as well. What I particularly appreciate about it is that it makes writing CSS simpler — most of CSS3 is about making your page look prettier with less markup and better semantics, but little attention has been paid to making the CSS itself simpler, clearer, and more elegant.

    Nice work.

    May 18th, 2010 at 17:01

  6. semper

    Thanks, great work (as always), but there’s one point…

    > 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.

    I wonder if these are real reasons for it to have a -moz- prefix? Compare

    /* Level 2 */
    section section h1, section article h1, section aside h1, section nav h1,
    article section h1, article article h1, article aside h1, article nav h1,
    aside section h1, aside article h1, aside aside h1, aside nav h1,
    nav section h1, nav article h1, nav aside h1, nav nav h1, {
    font-size: 20px;
    }

    with

    /* Level 2 */
    -moz-any(section, article, aside, nav)
    -moz-any(section, article, aside, nav) h1,
    -webkit-any(section, article, aside, nav)
    -webkit-any(section, article, aside, nav) h1,
    -o-any(section, article, aside, nav)
    -o-any(section, article, aside, nav) h1 {
    font-size: 20px;
    }

    Yes, second is still shorter, but you know what I mean. I agree the prefix is useful for something like gradients, where different interpretations and different syntaxes are possible, but here — isn’t it redundant?

    May 19th, 2010 at 03:02

    1. voracity

      It would be great if you do the equivalent of “:any” on vendor prefixes. For example:

      /* Level 2 */
      -[moz,webkit,o,none]-any(section, article, aside, nav)
      -[moz,webkit,o,none]-any(section, article, aside, nav) h1 {
      font-size: 20px;
      }

      This would make life so much easier for a whole heap of things…

      May 19th, 2010 at 04:52

      1. voracity

        Actually, extending this idea slightly:

        .box {
        border-[left,top]: white 1px solid;
        border-[right,bottom]: black 1px solid;
        }

        May 19th, 2010 at 04:56

        1. CyberSkull

          I like your idea! That would simplify so many definitions! :D

          July 7th, 2010 at 22:11

    2. Magne Andersson

      The prefix is required until a spec has reached Candidate Recommendation status, per CSS WG. We must have it on affected properties.

      May 19th, 2010 at 08:23

      1. zoe somebody

        While working on implementing a new HTML5 default markup scheme I discovered the Firefox UA stylesheet is already actually using the any() selector to adjust the size of h1 tags nested in html5 sectioning container as posited in the article above (from html.css):

        h3, *:-moz-any(article, aside, nav, section) *:-moz-any(article, aside, nav, section) h1 { display: block; font-size: 1.17em; font-weight: bold; margin: 1em 0; }

        While testing my markup scheme before styling anything I discovered that the h1 tags were not all the same size in FF vs every other browser. Inded, the nested h1’s were being sized down to h3’s and h4’s.

        While I for one really appreciate the any() selector and would like to use it for this very reason, implementing this in the UA stylesheet is unfortunate because now it is yet another thing that needs normalized for between browsers.

        I would push for the any() selector to become a part of the spec, but I would NOT like any extra formatting applied by the browsers until that extra formatting is standardized.

        Just thought I would post this here since this was the first search that came up as I started figuring this out.

        August 28th, 2011 at 22:43

        1. Paul Rouget

          This is not any extra formatting. This is part of the spec (nested headers are smaller). The fact we use :-moz-any doesn’t change anything. We could have used a more complex selector to achieve the same thing.

          August 29th, 2011 at 02:24

  7. semper

    Is this a MUST in the sense of RFC 2119? Or what? I mean, what’s the real sense of it?
    For me, Web is so great because decisions here tend to be so much rational, not business-drived, or marketing-drived, or whatever-else-drived.
    The question of prefixes, btw, had been rised and actively discussed before (see http://www.quirksmode.org/blog/archives/2010/03/css_vendor_pref.html for example).

    May 19th, 2010 at 14:37

    1. Magne Andersson

      It’s a CSS WG decision, so yes, it is a MUST.

      May 20th, 2010 at 00:59

  8. Giorgio

    vendor prefixes are a good thing because not all the implementations shows the same result, especially on non-recommended features

    but if css provide a media query for browser sniffing

    @media user-agent matches(/blabla/) { }

    prefixes can be removed… i hate them, but now are the only solution

    May 19th, 2010 at 15:49

  9. Matzipan

    Why would you want to use this anyway? To me it’s a useless selector, why would you want to have combination lists? It’s the developer’s job to keep his css tidy, not the browser to add some more features and slow down.

    June 23rd, 2010 at 10:57

  10. […] 원저자: Paul Rouget – 원문으로 가기 […]

    June 24th, 2010 at 08:30

  11. ZhouQi

    how about the performance?

    July 8th, 2010 at 20:47

  12. Steve

    I personally think that the any() selector would be great addition to CSS as long as it has no hits on page loading and rendering times. On the downside if it does get accepted I suppose it might get into IE15, maybe, and with bugs.
    Thanks for explaining so concisely.

    December 23rd, 2010 at 09:23

  13. […] with category names is not ideal. To make life easier, and your CSS some-more readable, Mozilla proposed a -any() pseudo selector. Using -any() we could rewrite a formula above like […]

    April 8th, 2011 at 01:20

  14. Anton Agestam

    I’d like the syntax to be more intuitive, why not drop the entire key-word-stuff and put like this:

    (section|nav|aside) (section|nav|aside) h1{font-size:20px;}

    April 11th, 2011 at 05:19

  15. Lars Gunther

    Isn’t the colons missing in front of -moz-any in the example code?

    June 29th, 2011 at 08:42

  16. […] -moz-any() selector grouping has been introduced by Mozilla but it’s not part of any CSS specification (yet?); it’s […]

    August 17th, 2011 at 22:45

  17. Poderwac

    thanks for these hacks, it’s exactly what I was looking for… I just hope that they are working with firefox 7 as well.

    October 3rd, 2011 at 06:21

  18. Dave

    That’s been brought up many times before, under the name “CSS Variables”. It was decided, though, that this should not be part of the CSS standard, at least not CSS3 and below.

    (Presumably it’s because CSS is supposed to be a very easy and simple language, which is good, but still limits you in some areas.)
    4G LTE Phones

    November 19th, 2011 at 09:57

  19. […] des W3C[2] http://www.w3.org/TR/selectors4/Selectors Level 4, W3C Working Draft[3] http://hacks.mozilla.org/2010/05/moz-any-selector-grouping/Mozillas Vorschlag für den -moz-any()-Selektor[4] http://dev.w3.org/csswg/css4-text/Selectors […]

    February 13th, 2012 at 08:38

Comments are closed for this article.