Search code examples
cssnamespacescss-selectorspseudo-class

Can a CSS pseudo-class be namespaced?


When using namespaces in CSS, you can select, for example, any div element in "any or no namespace" by using a namespaced type selector:

*|div

Is it valid CSS to namespace a pseudo-class? For example:

*|:first-child

It seems to work in WebKit based browsers, and it seems to not work in IE9 (below IE9 does not support namespaces at all) and Firefox. I don't care what browsers it does/doesn't work in, I just need to know whether it is a valid construct.

Here's a fiddle.

From what I can make out in the CSS grammar, it is not valid. But I may be misreading the grammar.


Solution

  • Namespaces, as part of the document language, do not apply directly to pseudo-classes or pseudo-elements, as they're defined in CSS and not the document language (e.g. XML). Element types and attributes, however, are defined in the document language as opposed to CSS, which is why they can be namespaced. Consequently, in a sequence of simple selectors, the universal selector specifically means "any type".

    The universal selector is only implied for other simple selectors and pseudo-elements when used without a namespace (this is why selectors like .foo, #target, [type="text"], :first-child and ::before are valid, and generally used with languages like HTML where CSS is most commonly used for styling). From the spec:

    If a universal selector represented by * (i.e. without a namespace prefix) is not the only component of a sequence of simple selectors selectors or is immediately followed by a pseudo-element, then the * may be omitted and the universal selector's presence implied.

    Therefore, in your example, the selector is invalid because there's neither a universal selector or a type selector between the | and the ::

    /* These are all invalid */
    *|:first-child
    ns|::first-letter
    |::before
    

    If you specify a namespace, you must specify the universal selector if you don't select a specific type instead:

    *|*:first-child
    *|*::before
    

    The same goes when selecting elements in an ns namespace:

    ns|*:first-child
    ns|*::before
    

    Or when selecting elements that are not in a namespace:

    |*:first-child
    |*::before