Sun. May 3rd, 2026

The <html> element, the foundational root of every web document, serves as the ultimate container for all other content. While seemingly straightforward to style using the basic html element selector, the evolving landscape of Cascading Style Sheets (CSS) has introduced a plethora of sophisticated and often unconventional methods to target this crucial element. A recent exploration, building upon an exercise by Temani Afif, delves into a range of these selectors, revealing approaches from the widely adopted to the purely academic, underscoring the depth and flexibility inherent in modern CSS. This analysis examines the utility, technical underpinnings, and broader implications of these diverse targeting strategies within the context of contemporary web development.

The Foundational Element: <html> and Basic Targeting

At its core, the <html> element represents the root of an HTML document, encapsulating the entire page content. It is the parent of both the <head> and <body> elements, making it the most fundamental structural component. Historically, styling the <html> element directly with the html selector has been the simplest and most common approach. This method, carrying a specificity score of 0-0-1 (type selector), applies styles directly to the document root, often used for global declarations such as font sizes, background colors, or box-sizing rules.

For decades, html /* styles */ remained the primary and most intuitive way to interact with the document root from a styling perspective. Its simplicity belies its importance, as it provides the initial cascade context for many inherited properties across the entire document. However, as CSS evolved, particularly with the advent of custom properties and more complex layout systems, the need for selectors with different specificity levels and semantic implications became apparent, paving the way for alternatives.

:root – The Semantic Choice for Global Styling

One of the most significant advancements in targeting the document root is the :root pseudo-class. Defined in the CSS Selectors Level 3 specification, :root matches the root element of the document. In an HTML document, this is invariably the <html> element. Its introduction provided a semantically distinct and technically advantageous alternative to the plain html selector, particularly for defining global variables.

The primary practical advantage of :root lies in its specificity. As a pseudo-class, :root carries a specificity score of 0-1-0, which is higher than that of an element selector (0-0-1). This elevated specificity means that styles declared on :root are less likely to be overridden by general element selectors, ensuring robust global declarations. This characteristic is particularly valuable when declaring CSS Custom Properties (often referred to as CSS variables), which are designed to be inherited globally and overridden selectively.

Example:

:root 
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  font-size: 16px;
  line-height: 1.5;

By convention and strong recommendation from the web development community, global custom properties are almost universally declared on :root. This practice leverages the pseudo-class’s higher specificity and ensures that these variables are available throughout the document’s cascade. While one could technically declare them on html, :root offers a clearer semantic intent for global scope and reduces potential conflicts.

The concept of :root extends beyond HTML, as it is designed to match the root element of any XML document. While HTML is the most prevalent XML-based document format encountered by web developers, other XML documents, such as SVG (Scalable Vector Graphics) or custom XML feeds rendered in browsers, also adhere to this principle. This broader applicability underscores its fundamental role in the CSS specification. The widespread browser support for :root across all modern engines – including Chrome, Firefox, Safari, Edge, and Opera – ensures its reliability and makes it a cornerstone of modern CSS development, especially for theme management and design system implementation.

Modern Scoping: :scope and CSS Nesting (&)

The evolution of CSS has increasingly focused on modularity and developer experience, leading to the introduction of powerful features like the @scope at-rule and CSS Nesting. These advancements bring new ways to define and reference scope, including the document root.

:scope in the Global Context

The :scope pseudo-class, while often associated with the new @scope at-rule, has a distinct behavior when used outside of it. When :scope is declared at the top level of a stylesheet, it matches the global scope root, which is effectively the <html> element. This behavior makes it functionally equivalent to :root in the absence of a custom scope definition. The original article playfully suggests a preference for :scope over :root for global variables, arguing for its semantic alignment with "global scope," though acknowledging no practical difference.

The true power and intended use of :scope emerge within the recently standardized @scope at-rule. @scope allows developers to define a custom scope for styles, effectively containing them within a specific part of the document tree and preventing "scope creep" – where styles inadvertently affect elements outside their intended area.

Example of @scope:

@scope (.card) 
  :scope  /* Selects the .card element */ 
  h2  /* Selects h2 elements within .card */ 

In this context, :scope refers to the element that defines the custom scope (e.g., .card). This capability is transformative for component-based architectures, allowing for more robust and isolated styling without resorting to complex naming conventions or shadow DOM. The @scope at-rule and its associated :scope pseudo-class reached baseline browser support in late 2023 and early 2024, marking a significant milestone in CSS modularity.

The & Selector and Unnested Contexts

Another recent addition to the CSS toolkit is CSS Nesting, which allows developers to nest style rules within other rules, mimicking the structure of HTML and improving readability and maintainability. A key component of CSS Nesting is the & selector.

Normally, the & selector is used to concatenate the current selector with a nested selector, allowing for flexible and powerful combinations. For example:

.button 
  color: white;
  &:hover  /* Selects .button:hover */
    background-color: blue;
  

However, a lesser-known behavior of & is its function when used in an unnested context, or when it implicitly refers to the root scope. When & is not part of a nested rule, it simply selects the scope root. Outside of an @scope block, this root is the <html> element. This peculiar characteristic means & /* styles */ can also target the <html> element, providing yet another, albeit unconventional, method. This behavior, while technically valid, is not recommended for targeting the <html> element due to potential confusion and its primary role in nesting. Its utility here is more an academic observation of CSS parsing rules rather than a practical application. CSS Nesting, including the & selector, achieved widespread browser support in 2023, rapidly changing how developers structure their stylesheets.

The Power of Relational Selectors: :has(head) and :has(body)

The :has() pseudo-class, often colloquially referred to as the "parent selector," represents one of the most anticipated and powerful additions to CSS in recent memory. It allows developers to select an element based on its descendants, meaning an element can be styled if it has a particular child or grandchild. While its primary applications are far-reaching and practical, its use in :has(head) or :has(body) provides an interesting, albeit impractical, way to target the <html> element.

According to HTML specifications, the <html> element is the only element permitted to directly contain a <head> element and a <body> element as its immediate children. Any other element attempting to contain <head> or <body> would result in invalid HTML, which browsers typically attempt to correct, often by moving these elements to their correct positions under <html>.

Given this structural constraint, the selectors :has(head) and :has(body) can only logically resolve to the <html> element. If an element "has" a <head> or <body> as a descendant, that element must, by definition of valid HTML, be the <html> element itself.

Example:

:has(head) 
  /* This will apply styles to the <html> element */


:has(body) 
  /* This will also apply styles to the <html> element */

While technically correct, using :has(head) or :has(body) to target <html> is highly impractical. It introduces unnecessary complexity and cognitive load compared to the straightforward html or :root selectors. Its main value in this discussion is to highlight the versatility and expressive power of the :has() pseudo-class itself.

The :has() pseudo-class gained robust browser support across Chrome, Firefox, Safari, and Edge in late 2022 and early 2023, following years of anticipation. Its introduction has unlocked new possibilities for conditional styling that previously required JavaScript, such as styling a parent element if it contains an image, an empty state, or a specific form input. For instance, section:has(h1) can style a section only if it contains an <h1>. While its application to <html> is more of a technical curiosity, :has() stands as a revolutionary feature for responsive design, dynamic layouts, and reducing reliance on JavaScript for presentational logic. It allows developers to write more declarative and maintainable CSS, moving closer to a truly semantic web.

Unconventional Approaches: :not(* *) and :not(* > *)

Beyond the practical and semantically driven selectors, CSS offers pathways to target the <html> element through highly unconventional and purely academic combinations, demonstrating the logical gymnastics possible within the selector engine. These methods, while utterly impractical for real-world development, serve as excellent illustrations of CSS selector mechanics.

:not(* *)

This selector utilizes the :not() pseudo-class in conjunction with the universal selector (*) and the descendant combinator ( ).

  • The universal selector (*) matches any element.
  • The descendant combinator (`) selects elements that are descendants of another element. Thus, selects any element that is a descendant of *any* other element. Essentially, it selects every element *except* theelement itself, as` has no parent.
  • The :not() pseudo-class then inverts this selection. So, :not(* *) selects any element that is not a descendant of another element. The only element that fits this description is the <html> element, as it is the absolute root and has no parent.

Example:

:not(* *) 
  /* Applies styles to the <html> element */

This selector is a verbose and inefficient way to target the <html> element. Its specificity is 0-1-0, matching that of :root, due to the :not() pseudo-class. However, its readability is extremely low, and it offers no practical advantage over html or :root.

:not(* > *)

This variation introduces the child combinator (>) into the :not() expression.

  • * > * selects any element that is a direct child of another element. For example, <body> is a direct child of <html>, and <h1> is a direct child of <body>.
  • Therefore, :not(* > *) selects any element that is not a direct child of another element. Similar to the previous example, the only element in a well-formed HTML document that meets this criterion is the <html> element itself, as it has no parent element, and thus cannot be a direct child of anything.

Example:

:not(* > *) 
  /* Also applies styles to the <html> element */

This selector, humorously described as producing a "cute bird" in the original article, further exemplifies the extreme flexibility of CSS selectors. Like :not(* *), it possesses a specificity of 0-1-0 and is purely of academic interest, offering no practical benefit for real-world styling of the <html> element. Both :not(* *) and :not(* > *) highlight the power of combinators and pseudo-classes to express complex relationships within the document tree, even if the resulting combination for <html> targeting is overly convoluted.

Specificity, Performance, and Best Practices

When choosing a selector to target the <html> element, several factors come into play, including specificity, readability, and maintainability.

  • Specificity:
    • html: 0-0-1 (Element selector)
    • :root: 0-1-0 (Pseudo-class)
    • :scope (global): 0-1-0 (Pseudo-class)
    • & (unnested): 0-1-0 (Pseudo-class, behaves like root)
    • :has(head) / :has(body): 0-1-0 (Pseudo-class)
    • :not(* *) / :not(* > *): 0-1-0 (Pseudo-class)

From a specificity standpoint, :root, :scope, &, :has(head), :has(body), and the :not() combinations all share the same higher specificity (0-1-0) compared to the basic html selector (0-0-1). This means that a style declared on :root will override a conflicting style declared on html if both target the same property. This is a key reason why :root is preferred for global custom properties, as it ensures they take precedence over more general declarations.

  • Performance: For targeting a single element like <html>, the performance difference between these selectors is negligible in modern browsers. Browser rendering engines are highly optimized to process even complex selectors quickly. Performance concerns typically arise with extremely broad or frequently recalculating selectors in very large DOM trees, which is not the case here.

  • Best Practices:

    • For general styling of the <html> element (e.g., default font, background), html remains perfectly acceptable due to its simplicity and clarity.
    • For declaring global CSS Custom Properties and establishing a global scope for variables, :root is the universally recommended and industry-standard approach. Its higher specificity and clear semantic intent make it the ideal choice.
    • While :scope and & can target <html> in specific contexts, their primary utility lies within the @scope at-rule and CSS Nesting, respectively. Using them globally for <html> targeting can be confusing and deviate from their intended purpose.
    • Selectors like :has(head), :has(body), :not(* *), and :not(* > *) should be considered purely academic or illustrative. They offer no practical advantages, diminish readability, and can introduce unnecessary complexity. The :has() pseudo-class itself is incredibly powerful for other use cases but not for styling <html> directly.

The developer community strongly advocates for clarity and maintainability. Choosing the simplest, most direct, and semantically appropriate selector is always the best practice. For <html> element targeting, this primarily means html for basic styles and :root for global custom properties.

The Evolving Landscape of CSS

The journey through these varied selectors for the <html> element underscores the dynamic nature of CSS development. The W3C CSS Working Group continually refines and expands the language, introducing features that address modern web development challenges, from modularity and component-based design to enhanced expressive power.

The introduction of :root provided a more robust way to manage global styles and variables. The recent baseline status of @scope and :has() marks a paradigm shift in how developers approach styling, enabling more encapsulated, conditional, and semantic CSS without resorting to JavaScript or complex build processes. CSS Nesting, with its & selector, streamlines stylesheet organization and enhances readability.

While some of the explored selectors for <html> are more theoretical curiosities than practical tools, they collectively illustrate the profound depth and flexibility of CSS. Understanding these mechanisms, both conventional and unconventional, empowers developers to write more precise, efficient, and maintainable stylesheets. As web technologies continue to advance, the ability to judiciously select and apply styles to the document’s root, and indeed any element, remains a fundamental skill for crafting robust and engaging digital experiences. The ongoing evolution of CSS promises even more powerful and elegant solutions, further solidifying its role as the backbone of visual web design.

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *