CSS selectors level 4
Tags: frontenddev, selectors, programming, css
Published: 2019-07-08 18:07:32

---
title: CSS selectors level 4
published: true
tags: front-end-developmen,selectors,programming,css
canonical_url: https://blog.logrocket.com/css-selectors-level-4-b5da36bcd54c
---

![](https://cdn-images-1.medium.com/max/1024/1*eYS388NUetsDByxTD4EEfw.png)

Selectors are a core part of CSS. They allow you to do things like select all the elements of a certain type:
```jsx
div {
  /* some styles to apply to all div elements */
}
```
Or you can select an element that is the last child of its parent:
```jsx
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:
```jsx
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:
```jsx
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](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#Specifications) 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](https://drafts.csswg.org/selectors-4/) 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](https://caniuse.com/#home) 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.

[![](https://cdn-images-1.medium.com/max/1024/1*GPjaPKNNUYHU8EsA3Z0JGA.png)](https://logrocket.com/signup/)

### Logical combinations

This category includes selectors that work by combining other selectors.

#### :not(selector1, selector2, …)

[Browser support](https://caniuse.com/#feat=css-not-sel-list)

It selects elements that don’t match any of the selectors of the list that it takes as an argument. For example:
```jsx
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:
```jsx
p:not(.beginning):not(.middle) {
  color: red;
}
```
{% codepen https://codepen.io/eh3rrera/pen/xMGxvY %}
#### :is(selector1, selector2, …)

[Browser support](https://caniuse.com/#feat=css-matches-pseudo)

It selects elements that match any of the selectors of the list that takes as an argument. For example:
```jsx
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](https://github.com/w3c/csswg-drafts/issues/3258) (which was the [only browser with full support for this selector](https://caniuse.com/#feat=css-matches-pseudo)), 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:
```jsx
p:-webkit-any(.beginning, .middle) {
  color: blue;
}

p:-moz-any(.beginning, .middle) {
  color: blue;
}
```
{% codepen https://codepen.io/eh3rrera/pen/daYRLJ %}
#### :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:
```jsx
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;
}
```
{% codepen https://codepen.io/eh3rrera/pen/daYzZg %}
#### :has(relativeSelector1, relativeSelector2, …)

[Browser support](https://caniuse.com/#feat=css-has) (at the time of this writing, this selector is not supported by any browser yet.)

This selector takes a[relative selector](https://drafts.csswg.org/selectors-4/#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:
```jsx
p:has(strong, em) {
  color: red;
}
```
Will give all p elements that contain either <strong> or <em>tags, a red color.
{% codepen https://codepen.io/eh3rrera/pen/QYjmYX %}
### Attribute selectors

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

#### [foo=”bar” i]

[Browser support](https://caniuse.com/#feat=css-case-insensitive)

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

For example:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/pGjVEg %}
#### [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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/yZYjbJ %}
### Linguistic pseudo-classes

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

#### :dir(ltr)

[Browser support](https://caniuse.com/#search=dir)

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:
```jsx
p:dir(ltr) {
  background-color: red;
}
```
Will set the background color of all p elements with left-to-right directionality to red.
{% codepen https://codepen.io/eh3rrera/pen/GzpdwV %}
#### :lang(zh, “\*-hant”)

[Browser support](https://caniuse.com/#search=%3Alang) (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](https://drafts.csswg.org/selectors-4/#language-range) 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:

```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/YByjzp %}
### Location pseudo-classes

This category includes selectors related to hyperlinks.

#### :any-link

No [can I use](https://caniuse.com/#home) 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:
```jsx
a:any-link {
  color: red;
}
```
Will give all of the a elements with an href attribute, a red color.
{% codepen https://codepen.io/eh3rrera/pen/vbNaeJ %}
#### :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:
```jsx
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).
{% codepen https://codepen.io/eh3rrera/pen/GzpBwG %}
### User action pseudo-classes

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

#### :focus-within

[Browser support](https://caniuse.com/#feat=css-focus-within)

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:

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

Will add a border around the input box when it receives focus.
```jsx
form:focus-within {
  border: 2px solid;
}
```
{% codepen https://codepen.io/eh3rrera/pen/BMoGWx %}
#### :focus-visible

[Browser support](https://caniuse.com/#feat=css-focus-visible)

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:
```jsx
/* 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.
{% codepen https://codepen.io/eh3rrera/pen/KJdbMp %}
### Input pseudo-classes

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

#### :read-write and :read-only

[Browser support](https://caniuse.com/#feat=css-read-only-write)

: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:
```jsx
: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.
{% codepen https://codepen.io/eh3rrera/pen/JxGXWw %}
#### :placeholder-shown

[Browser support](https://caniuse.com/#feat=css-placeholder-shown)

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

For example:
```jsx
input:placeholder-shown {
  color: red;
}
```
Will give the placeholder text of an `<input>` element (only the placeholder text) a red color.
{% codepen https://codepen.io/eh3rrera/pen/jdWrbp %}
#### :default

[Browser support](https://caniuse.com/#feat=css-default-pseudo)

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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/wNMWjx %}
#### :indeterminate

[Browser support](https://caniuse.com/#feat=css-indeterminate-pseudo)

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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/yZeaBL %}
#### :valid and :invalid

[Browser support](https://caniuse.com/#feat=form-validation)

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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/xMZEjp %}
#### :in-range and :out-of-range

[Browser support](https://caniuse.com/#feat=css-in-out-of-range)

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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/RvroLN %}
In some cases, these selectors will have the same effect as :valid and :invalid.

#### :required and :optional

[Browser support for :required](https://caniuse.com/#feat=form-validation)

[Browser support for :optiona](https://caniuse.com/#feat=css-optional-pseudo)l

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:
```jsx
input:optional {
  color: gray;
}

input:required {
  color: red;
}
```
Will give the element required elements a red color and optional elements a gray color.
{% codepen https://codepen.io/eh3rrera/pen/QYyGRQ %}
### 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](https://caniuse.com/#feat=css-nth-child-of) (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](https://css-tricks.com/examples/nth-child-tester/) to understand the difference and learn more about the [An+B notation syntax](https://drafts.csswg.org/css-syntax-3/#anb-microsyntax).

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:

```jsx
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:

```jsx
: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):
{% codepen https://codepen.io/eh3rrera/pen/NoxgEE %}
### 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:

<table><colgroup></colgroup><colgroup><col span="2"></colgroup><colgroup><col class="selected"></colgroup><tbody><tr><th><span class="pln"><span class="pln"><span class="hljs-attribute">ID</span></span></span></th><th><span class="typ"><span class="typ">Description</span></span></th><th><span class="typ"><span class="typ">Price</span></span></th></tr><tr><td><span class="lit"><span class="lit"><span class="hljs-number">1</span></span></span></td><td><span class="typ"><span class="typ">Computer</span></span></td><td><span class="pln"><span class="pln"><span class="hljs-variable">$999</span></span></span></td></tr><tr><td><span class="lit"><span class="lit"><span class="hljs-number">2</span></span></span></td><td><span class="typ"><span class="typ">Tablet</span></span></td><td><span class="pln"><span class="pln"><span class="hljs-variable">$499</span></span></span></td></tr>
</tbody></table>

The following style:
```jsx
col.selected || td {
 background-color: lightyellow;
}
```
Will give cells (`<td>` elements) that belong to the selected column (_Price_) a light yellow background color.
{% codepen https://codepen.io/eh3rrera/pen/xMZLQY %}
#### :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:
```jsx
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.
{% codepen https://codepen.io/eh3rrera/pen/RvrLwm %}
### 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](https://drafts.csswg.org/selectors-4/) 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):

- [:target-within](https://drafts.csswg.org/selectors-4/#target-within-pseudo)
- [:scope](https://drafts.csswg.org/selectors-4/#the-scope-pseudo) (don’t confuse it with [scoped styles](https://caniuse.com/#feat=style-scoped))
- [Time-dimensional pseudo-classes](https://drafts.csswg.org/selectors-4/#time-pseudos) (you can know more about them [here](http://css4.rocks/time-dimensional-pseudo-classes.php))
- [:blank](https://drafts.csswg.org/selectors-4/#blank)
- [:user-invalid](https://drafts.csswg.org/selectors-4/#user-pseudos)

But definitely keep an eye on these and the rest of the Level 4 selector.
* * *
### Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps

[![](https://cdn-images-1.medium.com/max/1024/1*s_rMyo6NbrAsP-XtvBaXFg.png)](https://logrocket.com/signup/)<figcaption><a href="https://logrocket.com/signup/">https://logrocket.com/signup/</a></figcaption>

[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single page apps.

[Try it for free.](https://logrocket.com/signup/)
* * *
The post [CSS selectors level 4](https://blog.logrocket.com/css-selectors-level-4-b5da36bcd54c/) appeared first on [LogRocket Blog](https://blog.logrocket.com).