Family man, Java and JavaScript developer. Swift and VR/AR hobbyist. Like books, movies, and still trying many things. eherrera.net

Selectors are a core part of CSS. They allow you to do things like select all the elements of a certain type:

div { /* some styles to apply to all div elements */ }

Or you can select an element that is the last child of its parent:

ul li:last-child { /* some styles to apply to only the last child of a list */ }

Of course, they also allow you to do more complex things, like select all of the children of a list except its last child.

In fact, there’s more than one way to do that, some more complex than others.

For example, compare this:

ul li { /* Styles to apply to all children */ } ul li:last-child { /* Styles to reset the previous styles because they don’t apply to the last child */ }

To this:

ul li:nth-last-child(n+2) { /* Styles to apply to all children except the last one */ }

ul li is an example of a level 1 selector.

last-child and nth-last-child are examples of level 3 selectors.

You can think of levels as versions of the CSS selector specification, where each level adds more powerful selectors.

In this article, I’ll give you an overview of the last generation of selectors, level 4, according to the Editor’s Draft specification as of January 2019, in the following categories:

Logical combinations

Attribute selectors

Linguistic pseudo-classes

Location pseudo-classes

User action pseudo-classes

Input pseudo-classes

Tree-structural pseudo-classes

Grid-structural selectors

At the time of this writing, the specification for level 4 selectors is in draft status. It may change until it reaches the official recommendation status, and you’ll find that many selectors are either not supported by some browsers or they need to be prefixed (with :-moz- or :-webkit- ).

For each selector, I’ll give a link to its can I use page so you can see what browsers support it (if it’s available), a brief description, an example, and a link to a Codepen so you can try it (even if it doesn’t work right now, since it may change in the future).

With that in mind, let’s start with the selectors of the logical combinations category.

Logical combinations

This category includes selectors that work by combining other selectors.

:not(selector1, selector2, …)

Browser support

It selects elements that don’t match any of the selectors of the list that it takes as an argument. For example:

p:not(.beginning, .middle) { color: red; }

Will give all p elements that don’t have the classes beginning and middle , a red color.

The level 3 version of this selector only allows one selector instead of a list of two or more. For example, the above style can be written as:

p:not(.beginning):not(.middle) { color: red; }

See the Pen

:not pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:is(selector1, selector2, …)

Browser support

It selects elements that match any of the selectors of the list that takes as an argument. For example:

p:is(.beginning, .middle) { color: blue; }

Will give all p elements that have the classes beginning and middle , a blue color.

One of the most significant changes since the last working draft version is that the :matches() selector was renamed to :is() and deprecated it Safari (which was the only browser with full support for this selector), so it makes a better pairing with :not() , its opposite.

:matches() can be implemented as an alias for :is() if needed for backwards-compatibility. However, :matches() was formerly called :any() , so most browsers support this pseudo-class with a prefix:

p:-webkit-any(.beginning, .middle) { color: blue; } p:-moz-any(.beginning, .middle) { color: blue; }

See the Pen

:is pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:where(selector1, selector2, …)

At the time of this writing, this selector is not supported by any browser yet.

It has the same syntax and functionality as :is() , but neither the selector nor any of its arguments contribute to the specificity of the selector, which is always zero.

Specificity is the weight applied to a CSS rule. If two selectors apply to the same element, the one with higher specificity wins. If multiple rules have equal specificity, the last rule found in the CSS document is applied to the element.

This selector can be used to implement filters and override the style declarations associated with an element.

The specification gives the following example:

a:not(:hover) { text-decoration: none; } nav a { /* Has no effect */ text-decoration: underline; } /* With the new :where Level 4 selector */ a:where(:not(:hover)) { text-decoration: none; } nav a { /* Should work */ text-decoration: underline; }

See the Pen

:where pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:has(relativeSelector1, relativeSelector2, …)

Browser support (at the time of this writing, this selector is not supported by any browser yet.)

This selector takes a relative selector list as an argument. It selects an element if any of the relative selectors (when evaluated as elements in scope) match the element.

For example:

p:has(strong, em) { color: red; }

Will give all p elements that contain either <strong> or <em> tags, a red color.

See the Pen

:has pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

Attribute selectors

This category includes selectors that work with an element’s attributes.

[foo=”bar” i]

Browser support

It selects an element whose foo attribute value is exactly equal to bar , regardless of its case.

For example:

p[class="text" i] { color: green; }

Will give all p elements whose class attribute has the values Text , TEXT , or text , among other combinations, a green color.

See the Pen

Case-insensitive selector by Esteban Herrera (@eh3rrera)

on CodePen.

[foo=“bar” s]

At the time of this writing, this selector is not supported by any browser yet.

It selects an element whose foo attribute value is exactly and case-sensitively equal to bar .

For example:

p[class="text" s] { color: green; }

Will give all p elements whose class attribute has the value text (not Text , for example), a green color.

See the Pen

Case-sensitive selector by Esteban Herrera (@eh3rrera)

on CodePen.

Linguistic pseudo-classes

This category includes selectors that work with language-related settings.

:dir(ltr)

Browser support

It selects elements with left-to-right directionality, where the document language specifies how directionality is determined. On the other hand, :dir(rtl) represents an element that has right-to-left directionality. Other values are not invalid but do not match anything.

For example:

p:dir(ltr) { background-color: red; }

Will set the background color of all p elements with left-to-right directionality to red.

See the Pen

:dir(ltr) pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:lang(zh, “*-hant”)

Browser support (at the time of this writing, the level 4 version for this selector is not supported by any browser yet)

It selects an element tagged as being either in Chinese (or any other language, just replace zh with any other language code) or written with traditional Chinese characters (or in any other character system, just replace *-hant with any other character code).

Actually, this selector can be used since CSS 2, however, wildcard language matching and comma-separated lists are new in level 4 selectors.

It accepts a comma-separated list of one or more language ranges as its argument. If the language range contains asterisks, they must be either correctly escaped ( :lang(es-\*) ) or quoted as a string ( :lang("es-*) ).

For example:

p:lang("*-CH") { background-color: red; }

Will set the background color of all p elements with one of the languages spoken in Switzerland ( CH represents Switzerland) to red.

See the Pen

:lang pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

Location pseudo-classes

This category includes selectors related to hyperlinks.

:any-link

No can I use page, but this selector is supported by most of the major browsers.

It selects all elements that have an href attribute (like <a> or <link> ). In other words, all of the elements that match the :link or :visited pseudo-classes.

For example:

a:any-link { color: red; }

Will give all of the a elements with an href attribute, a red color.

See the Pen

:any-link pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:local-link

At the time of this writing, this selector is not supported by any browser yet.

It selects elements that target the current URL. If the link’s target includes a fragment URL, then the fragment URL of the current URL must also match; if it does not, then the fragment URL portion of the current URL is not taken into account in the comparison.

For example:

a:local-link { text-decoration: none; }

Will prevent all of the a elements with an href attribute that targets the current page from being underlined (maybe they are part of a navigation menu).

See the Pen

:local-link pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

User action pseudo-classes

This category includes selectors for elements the user is acting on.

:focus-within

Browser support

It selects elements that either match the :focus pseudo-class (when the element has the focus) or have children that match :focus .

For example, assuming the following form:

<form>

<input type="text" id="name" placeholder="Enter your name" />

</form>

Will add a border around the input box when it receives focus.

form:focus-within { border: 2px solid; }

See the Pen

:focus-within pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:focus-visible

Browser support

It selects an element if it’s currently focused (it matches the :focus pseudo-class) and the browser determines that the focus should be made evident on the element, usually, with a focus ring.

The difference with :focus is subtle.

If :focus-visible matches, :focus will also match, but the opposite is not always true, it depends on the browser (if it has focus ring drawing enabled) and how the element was focused (via a mouse click versus keyboard tabbing).

Firefox implements this selector as the :-moz-focusring pseudo-class.

For example, in some cases, the following style:

/* Standard Level 4 selector */ :focus-visible { background-color: lightgray; } /* Level 4 selector for Firefox*/ :-moz-focusring { background-color: lightgray; }

Will be only applied if the element receives the focus via keyboard tabbing.

See the Pen

:focus-visible pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

Input pseudo-classes

This category includes selectors that apply to elements that take user input.

:read-write and :read-only

Browser support

:read-write selects elements whose value is mutable (like an <input> element that does not have the readonly attribute).

:read-only selects elements whose value is immutable (like an <input> element that has the readonly attribute).

However, these selectors don’t just select <input> or <textarea> elements, they select any element that can be edited by the user, such as a <p> element with the contenteditable attribute set to true .

For example:

:read-write { background-color: lightyellow; } :read-only { background-color: lightgray; } /* For Firefox */ :-moz-read-write { background-color: lightyellow; } :-moz-read-only { background-color: lightgray; }

Will set the background color of all mutable elements to lightyellow and lightgray for all immutable elements in a page.

See the Pen

:read-write and :read-only pseudo-classes by Esteban Herrera (@eh3rrera)

on CodePen.

:placeholder-shown

Browser support

It selects an input element that is currently showing placeholder text.

For example:

input:placeholder-shown { color: red; }

Will give the placeholder text of an <input> element (only the placeholder text) a red color.

See the Pen

:placeholder-shown pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:default

Browser support

It selects the element that is the default option in a group of related elements. Usually applies to buttons and select lists/menus.

For example:

input:default { box-shadow: 0 0 2px 2px green; } input:default + label { color: green; }

Will give to the default <input> element a green shadow and color to its label.

See the Pen

:default pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:indeterminate

Browser support

It selects elements whose value is in an indeterminate state. For example, radio and checkbox groups that contain no checked elements, or progress bars whose percent completion is unknown.

For example:

input[type="radio"]:indeterminate + label { color: red; }

Will give the labels of the radio elements in a group, a red color if there are no elements in the group that are checked.

See the Pen

:indeterminate pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:valid and :invalid

Browser support

They select elements whose contents or value is, respectively, valid or invalid according to their validity semantics. If the semantics are not defined (or cannot be defined), the element is neither :valid nor :invalid .

For example, for an input element of type email :

input:invalid { color: red; } input:valid { color: green;

Will give the text of the element a different color depending if the element contains a valid or an invalid email.

See the Pen

:valid and :invalid pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

:in-range and :out-of-range

Browser support

These selectors apply only to elements that have range limitations, for example, if it can have a defined minimum or maximum. If there are no such constraints, the element is neither :in-range nor :out-of-range .

For example, for an input element with a minimum value of 1 and a maximum value of 5:

input:out-of-range { color: red; } input:in-range { color: green; }

Will give the element a red color for any values greater than 5, and a green color for values between 1 and 5.

See the Pen

:in-range and :out-of-range pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

In some cases, these selectors will have the same effect as :valid and :invalid .

:required and :optional

Browser support for :required

Browser support for :optional

These selectors apply to form elements that are, respectively, required or optional before the form can be submitted. Elements that are not form elements are neither required nor optional.

For example:

input:optional { color: gray; } input:required { color: red; }

Will give the element required elements a red color and optional elements a gray color.

See the Pen

:required and :optional pseudo-class by Esteban Herrera (@eh3rrera)

on CodePen.

Tree-structural pseudo-classes

This category includes selectors that allow selection based on information that lies in the document tree but cannot be represented by other selectors, like the position of an element relative to its parent.

:nth-child(n [of selector]?) and :nth-last-child(n [of selector]?)

Browser support (at the time of this writing, the Level 4 version for this selector is not supported by any browser yet).

The :nth-child selector matches every element that is the nth child of its parent. :nth-last-child does the same but counting from the last child. You can play with this :nth tester to understand the difference and learn more about the An+B notation syntax.

At the beginning of this article, I showed you an example of :nth.last-child and I said it was a Level 3 selector. However, for Level 4, this selector accepts an optional of selector clause which filters the children to only those which match that selector.

In addition to being more powerful, sometimes, there can be differences due to the way the selector is declared. For example:

li.item:nth-child(-n+2)

Selects the first two <li> elements but only if they have the class item .

It’s not the same as:

:nth-child(-n+2 of li.item)

That selects the first two <li> elements that have the class item even if they are not the first two children on the list.

Try it (in a browser that supports this selector, like Safari):

See the Pen

:nth-child 1/2 by Esteban Herrera (@eh3rrera)

on CodePen.

See the Pen

:nth-child 2/2 by Esteban Herrera (@eh3rrera)

on CodePen.

Grid-structural selectors

This category includes selectors that work with columns of a table.

F | | E

At the time of this writing, this selector is not supported by any browser yet.

The column combinator selector ( || ) selects an element of type E that represents a cell in a table and belongs to a column represented by an element of type F .

For example, assuming the following table:

ID Description Price 1 Computer $999 2 Tablet $499

The following style:

col.selected || td { background-color: lightyellow; }

Will give cells ( <td> elements) that belong to the selected column (Price) a light yellow background color.

See the Pen

Column combinator selector by Esteban Herrera (@eh3rrera)

on CodePen.

:nth-col(An+B) and :nth-last-col(An+B)

At the time of this writing, this selector is not supported by any browser yet.

You can think of these selectors as the column version of :nth-child and :nth-last-child .

:nth-col(An+B) selects an element in a grid or a table that represents a cell of a column that has An+B-1 columns before it, for any positive integer or zero value of n .

:nth-last-col(An+B) selects an element in a grid or a table that represents a cell of a column that has An+B-1 columns after it, for any positive integer or zero value of n .

For example:

col.nth-col(1) { background-color: lightyellow; } col.nth-last-col(1) { background-color: lightgreen; }

Will give the first column of a table a light yellow background color, while the last column will have a light green background color.

See the Pen

:nth-col() and :nth-last-col() pseudo-classes by Esteban Herrera (@eh3rrera)

on CodePen.

Conclusion

Level 4 selectors allow you to declare complex selection rules in an easy way.

We have covered most of the selectors defined in the Editor’s Draft specification of January 2019, however, I have left out some selectors that are at risk of disappearing or changing soon, or there’s not much information about them (in addition to not being supported by any browser):

But definitely keep an eye on these and the rest of the Level 4 selector.

Is your frontend hogging your users' CPU? As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, https://logrocket.com/signup/ As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors. Modernize how you debug web apps — Start monitoring for free.