CSS Level 4 Selectors in depth

On the 29th September, CSSWG published its first draft of CSS Selectors Level 4. This means CSS4 is being worked on already!

Whats new?

Below is a quick overview of all the new features in CSS Selectors Level 4 (Including 3UI), which of course may change.

Pattern Meaning
E:not(s1, s2) an E element that does not match either compound selector s1 or compound selector s2
E:matches(s1, s2) an E element that matches compound selector s1 and/or compound selector s2
E[foo="bar" i] an E element whose foo attribute value is exactly equal to any (ASCII-range) case-permutation of bar
E:local-link an E element being the source anchor of a hyperlink of which the target is the current document
E:local-link(0) an E element being the source anchor of a hyperlink of which the target is within the current domain
E:current an E element that is currently presented in a time-dimensional canvas
E:current(s an E element that is the deepest :current element that matches selector s
E:past an E element that is in the past in a time-dimensional canvas
E:future an E element that is in the future in a time-dimensional canvas
E:indeterminate a user interface element E that is in an indeterminate state (neither checked nor unchecked)
E:default a user interface element E that
a user interface element E that
a user interface element E that
a user interface element E that
E:nth-match(n of selector) an E element, the n-th sibling matching selector
E:nth-match(n of selector) an E element, the n-th sibling matching selector
E:column(selector) an E element that represents a cell in a grid/table belonging to a column represented by an element that matches selector
E:nth-column(n) an E element that represents a cell belonging to the nth column in a grid/table
E:nth-last-column(n) an E element that represents a cell belonging to the nth column in a grid/table, counting from the last one
E /foo/ F an F element ID-referenced by an E element’s foo attribute
$E > F an E element parent of an E element
Pattern Meaning

E:not( s1, s2 )

This works the same as :not(s1) from the CSS3 spec, but now you can add a second selector:

input:not(input[type="submit"], input[type="reset"]){...}

E:matches( s1, s2 )

Matches a selector based on the element matching 1 and/or 2 selectors, simple:

a:matches(a.productLink, a.catLink) {...}

E[foo="bar" i]

This selects an element with an attribute “foo” with a values “bar”. The ending “i” meaning to ignore case of the attribute value, like how you would find in regex statements:

input[name="ProductID" i ] {...}

Would match something like:

<input name="ProductID" />
<input name="productid" />
<input name="PRODUCTID" />

E:local-link and E:local-link( 0 ) ( or E:local-link( n ) )

E:local-link selects an element that links to the same page it is on:


E:local-link(0) matches all links that link to a page within the same domain:


Any number greater than 0 refers to how many path segments there are, so you add as many as you need.

An important think to note is that the protocol (HTTP and HTTPS) can be different to match the same domain.

The domain name needs to be strictly the same, http://www.webmuse.co.uk would be considered different to http://webmuse.co.uk.

If the current page was http://www.webmuse.co.uk, and you have the following HTML:

        <li><a href="http://www.webmuse.co.uk">Home</a></li>
        <li><a href="http://www.webmuse.co.uk/blog/">Blog</a></li>
        <li><a href="http://www.webmuse.co.uk/blog/test/">Test</a></li>
        <li><a href="http://www.github.com/tomgrohl/">Github</a></li>

And the following CSS:

a:local-link{ background-color: #FFFFFF}

a:local-link(0){ border-radius: 8px;color: #000000}

a:local-link(1){ color: #000000; background-color: #FFFFFF}

a:local-link(2){ color: #C40000; background-color: #FFFFFF}

The Home link would get styles 1 and 2 because it is the current page and it links within the same domain.

The Blog link would get styles 2 and 3 as it links within the same domain and has 1 path segment.

The Test link would receive styles 2, 3 and 4 because it links within the same domain and has both 1 and 2 path segments.

The Github link would receive no styling as it is an external link.

This is one of the best features coming to CSS4. It means we don’t need to add classes to the body and the nav links like this:

<body class="home>

    <li><a class="homelink">Home</a></li>

E:current, E:current( s ), E:past, E:future

These selectors refer to elements relative to a time dimensional canvas, such as speech rendering of a HTML document.


This selector refers to an element that doesn’t have a state. For example a checkbox or radio button that isn’t checked or unchecked.


This refers to a element that is the default out of a set of similar elements. For example, a submit button in a group of buttons.

E:in-range and E:out-of-range

This applies to an element that has a range set against it. If you remember the new element types and Validation API that’s part of HTML5 / ECMA5, you can have an input element of range and set a min and a max value:

<input type="range" min="5" max="10" />

You would then use these selectors for when you are in range of those values, or when you go out of range.

E:required and E:optional

As mentioned previously, this is part of the new element types in HTML5, and applies to elements like the following:

<input type="text" required="required" />
<input type="text" optional="optional" />

E:read-only and E:read-write

E:read-only refers to elements that can’t have there contents altered, unless they have the contenteditable attribute of the HTML5 element is set to true.

Input elements, by default have a :read-write state, although you cane make them read only:

<input type="text" readonly="readonly" />

E:nth-match( n of selector )

This works like the :nth-child selector, but you can pass a selector list to it:

div:nth-match:( odd, .list, .list2 ){..}

Which is better than doing the following, and is easier to read:

div.list:nth-child(odd), div.list2:nth-child(odd) {...}

E:column( s [,s] )

This selectors matches elements that match the selector list passed to it. Something like:

table col:column( col.active, col.selected ) {...}

E:nth-column( n )

Matches columns that has n columns before it, for example:

table col:nth-column(odd){...}

table col.nth-column(2n+1){...}

E:nth-last-column( n )

Matches columns that has n columns after it, for example:

table col:nth-last-column(odd){...}

table col.nth-last-column(2n+1){...}

E /for/ F

This selects a element F that is ID-referenced by element E’s for attribute:

label /for/ input {...}


<label for="myname">Name: </label>

<input id="myname" type="text" />

$E > F

This selector is one of the best one that will be in CSS4 Selectors. Using the $ sign you can change the target of the element the CSS should apply to, effectively selecting the parent based on the child. So in the following example section would be styled and not div.active:

$section > div.active {...}

Some people probably won’t think this is that amazing, but there’s probably a lot of developers that have wanted to do this for a long time, myself included. The only easy way to do this would be to use jQuery.


Some of the new Selectors for CSS4 are good, some could be better, buts as its a first draft there’s room for needed improvement.

I’m not sure how I feel about the :local-link selector. I think it would be best to have :local-link(*) for all links, but I can see where they were coming from with :local-link(0), as it refers to a link with a minimum of 0 path segments. I’m just so used to seeing a * when selecting all elements.

Apart from that I can’t wait to start using CCS4 Selectors.

This entry was posted in Blog. Bookmark the permalink.

Comments are closed.