All the Different Ways to Select the <html> Element in CSS
The <html> element is the root of every web page, and in most projects it quietly does its job without much attention. Yet from a CSS perspective, there are multiple ways to select this element—some practical, some purely academic. Understanding these options can help you reason more clearly about the cascade, specificity, and browser behavior.
This article walks through the different selectors that can target the <html> element, why they work, and when (or if) you should use them in real-world projects.
Key Takeaways
- The most direct way to style the root element is the element selector
html { }, but it is not the only option. - CSS selectors such as :root, html:root, and combinations with universal selectors can also match the same element.
- Most alternative methods are more about specificity and clarity than offering new capabilities.
- For maintainable code, prefer clear, conventional selectors and reserve trickier approaches for debugging, demos, or very specific use cases.
Why Target the <html> Element at All?
Before diving into the selectors, it helps to clarify why you might want to style the <html> element in the first place. While a lot of global styles are placed on the <body>, the root element is still important for:
- Defining base font sizing using relative units like
rem - Setting CSS custom properties (variables) available across the entire document
- Controlling behaviors related to scrolling and viewport on some devices
- Applying global color themes or background settings
The root element is a reliable place to define project-wide defaults—especially font sizing and CSS variables—that every other component can inherit.
For teams managing design systems or large-scale web applications, knowing how to precisely target the root element is part of building predictable, maintainable CSS.
1. Using the Basic Element Selector
The Standard Approach: html { ... }
The most straightforward way to select the root element is the simple element selector:
html {
font-size: 16px;
background-color: #f5f5f5;
}
This selector:
- Has low specificity (0,0,0,1)
- Is supported in every browser
- Is immediately readable to any developer
For most production environments, this is the preferred way to target the <html> element unless you have a specific reason to do otherwise.
2. Using the :root Pseudo-Class
What is :root?
The :root pseudo-class matches the root element of the document. In an HTML document, :root and html select the same element. For example:
:root {
--brand-color: #0069d9;
--font-size-base: 16px;
}
This is functionally equivalent to:
html {
--brand-color: #0069d9;
--font-size-base: 16px;
}
Why Developers Prefer :root for Variables
While html and :root target the same node, :root is widely used for CSS custom properties because it emphasizes the idea of “global scope” for variables.
For example, in a design system you might define:
:root {
--color-primary: #1a73e8;
--color-secondary: #e37400;
--border-radius-base: 4px;
}
Then reuse these tokens across components:
.btn-primary {
background-color: var(--color-primary);
border-radius: var(--border-radius-base);
}
Using :root makes it visually obvious where global design tokens are defined, which improves maintainability for teams and agencies handling long-lived projects.
3. Combining html and :root
Selector: html:root
You can also combine the element selector and the pseudo-class:
html:root {
color: #222;
}
This selector is more specific than using html or :root alone. Both match the same element, but when combined:
- Specificity becomes 0,0,1,1 (one pseudo-class + one element)
- It will override simple
html { ... }or:root { ... }rules if they conflict
In practice, this is rarely needed in production code. However, it can be useful if you:
- Need a quick way to override an existing global rule without refactoring everything
- Are exploring how specificity works and want to see its effect on the cascade
4. Using the Universal Selector
Selector: *:root
The universal selector (*) matches any element, and when combined with :root, it still only matches the root element in an HTML document:
*:root {
background: #ffffff;
}
The result is effectively the same as :root, but technically:
- It is more verbose and not more expressive
- It can be slightly less efficient for the browser to parse (though negligible in modern engines)
Again, this is more of an academic curiosity than a recommended pattern. It demonstrates that selectors can be composed in different ways yet still resolve to the same element.
5. Attribute Selectors on the <html> Element
Using the lang Attribute
The <html> element frequently includes attributes like lang or dir. You can target it with an attribute selector, for example:
html[lang="en"] {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
Or even more specific:
html[lang^="en"] {
/* Matches en, en-US, en-GB, etc. */
line-height: 1.5;
}
This can be helpful if your site serves multiple locales and you want certain base styles or typographic decisions to vary by language.
Using the dir Attribute
For right-to-left (RTL) languages, you might see:
html[dir="rtl"] {
direction: rtl;
}
While there are newer logical properties and media queries that can help handle direction, attribute selectors on <html> remain a practical option on multilingual websites and applications.
6. Class and ID Selectors on <html>
Styling via Classes
Although less common, you can assign a class to the <html> tag and target it like any other element:
<html class="theme-dark">
With CSS:
html.theme-dark {
color-scheme: dark;
background-color: #111;
color: #f0f0f0;
}
This pattern is particularly useful for:
- Theme toggling (light vs dark mode)
- Applying environment-specific styles (e.g., a preview mode in a CMS)
Using an ID (Generally Not Recommended)
You can technically give the <html> element an ID:
<html id="root-html">
And target it with:
#root-html {
/* styles */
}
This works, but IDs have very high specificity and can make future overrides more difficult. For most business and enterprise codebases, classes are more flexible and maintainable than IDs for this purpose.
7. Less Practical but Possible Selectors
Descendant and Child Selectors
You might encounter or experiment with selectors like:
html:root html { ... }
However, in a valid HTML document, there is only one <html> element and it cannot be nested inside itself. As a result, such selectors are either redundant or match the same node in a way that does not provide any real-world advantage.
These patterns are typically used for:
- Testing CSS parsing and selector behavior
- Demonstrations or educational examples
Combining with Pseudo-Classes
Some pseudo-classes can be combined with html, such as :not(). For example:
html:not(.no-scroll) {
scroll-behavior: smooth;
}
This allows you to toggle behaviors via classes while keeping logic at the document root.
Conclusion
The <html> element can be selected in CSS using a variety of techniques: html, :root, combinations like html:root, universal selectors, attribute selectors, and even classes or IDs. From a browser’s perspective, many of these are equivalent in terms of which element they match; the differences lie in specificity, clarity, and intent.
For modern, maintainable projects, most teams will rely on:
- html for basic global layout and typography
- :root for CSS custom properties and design tokens
- Classes or attributes on <html> for theming, localization, or direction-based adjustments
Understanding these options is less about finding clever selector tricks and more about gaining precise control over the foundation of your page styles.
Need Professional Help?
Our team specializes in delivering enterprise-grade solutions for businesses of all sizes.
Explore Our Services →Share this article:
Need Help With Your Website?
Whether you need web design, hosting, SEO, or digital marketing services, we're here to help your St. Louis business succeed online.
Get a Free Quote