Beyond the Obvious: Hidden CSS Selectors for the <html> Element
Uncover hidden CSS selectors for the `<html>` element. Explore unique ways to target the document root using the nesting `&`, `:scope`, `:has()`, and `:not()` pseudo-classes.
It's common knowledge that the <html> element can be targeted using classic CSS selectors like html {} or :root {}. But what if we told you there are other, less obvious, and somewhat "hidden" selectors capable of achieving the same? Let's dive into some fascinating ways to select the root HTML element.
The Shortest Selector: The Nesting Selector (&)
Meet the one-character nesting selector &. When used at the top level, outside of a nested rule, it behaves much like :scope.
& {
font-size: 20px;
background: lightblue;
}
The :scope Selector
The :scope pseudo-class represents the root of a scoping context. When no specific scoping root is defined, it effectively targets the document's root, which is the <html> element.
:scope {
font-size: 20px;
background: lightblue;
}
Both & and :scope rely on their fallback behavior here: & acts like :scope when not nested, and :scope points to the document root when no other scoping root is present.
Leveraging Unique Child Elements with :has()
The <html> element is unique in that it's the only element with <head> and <body> as direct children. We can exploit this characteristic using the powerful :has() pseudo-class:
:has(head) {
font-size: 20px;
background: lightblue;
}
/* OR */
:has(body) {
font-size: 20px;
background: lightblue;
}
Targeting by Absence of a Parent with :not()
Another defining feature of the <html> element is its lack of a parent. This allows for some rather fancy selections using the :not() pseudo-class:
:not(* *) { /* Selects an element that is not a descendant of anything, i.e., has no parent */
font-size: 20px;
background: lightblue;
}
We can refine this further by adding the child combinator (>), creating a selector that might look like two eyes and a nose!
:not(* > *) { /* Selects an element that is not a child of anything */
font-size: 20px;
background: lightblue;
}
More Combinations and Explorations
The world of CSS selectors offers even more possibilities for exploration, combining these concepts:
:is(&) {
/* ... */
}
:where(&) {
/* ... */
}
&& {
/* Yes, you can append as many "&" as you want! */
}
&&&& {
/* ... */
}
:has(> body):has(> head) {
/* ... */
}
:has(body, head) {
/* ... */
}
/* etc... */
While these selectors might not find their way into everyday production code due to readability or specific browser support (especially for newer features like nesting &), they offer a fun and insightful exercise into the depth and flexibility of CSS selectors. It's a great way to explore the boundaries of what's possible!