CSS :root Pseudo Class
The :root CSS pseudo-class selects the elements that match the root element of the document. Read about the pseudo-class and try examples.
The :root pseudo-class matches the root element of the document — the single element that contains every other element on the page.
In an HTML document the root element is always <html>, so writing :root is equivalent to writing the html selector — with one important difference: :root has higher specificity. Because it's a pseudo-class, :root carries the same specificity as a class selector (0,1,0), while the plain html type selector has the lower specificity of a single element (0,0,1). When a rule on :root and a rule on html both target the same property, the :root rule wins.
In SVG and XML documents, :root matches whatever element sits at the top of that document tree, so it isn't tied to <html> there.
Why :root is worth knowing
You could almost always replace :root with html, so why does it exist and why is it everywhere in modern CSS? Two reasons:
- It is the home for CSS custom properties (variables). Declaring variables on
:rootmakes them available to every element on the page, since custom properties inherit down the tree. This is the single most common use of:roottoday. - Its higher specificity makes it a reliable place to set document-wide defaults that you don't want a stray
html { ... }rule to override.
Syntax
:root {
/* CSS declarations */
}Defining global CSS variables on :root
A custom property is any property whose name starts with two dashes (--brand-color). You read it back anywhere with the var() function. Putting these declarations on :root is the idiomatic way to create a single source of truth for colors, spacing, and fonts:
<!DOCTYPE html>
<html>
<head>
<style>
:root {
--brand: #8ebf42;
--gap: 1.5em;
}
h2 {
color: var(--brand);
}
p {
padding: var(--gap);
border-left: 4px solid var(--brand);
}
</style>
</head>
<body>
<h2>Theme driven by :root variables</h2>
<p>Change one value in :root and both elements update.</p>
</body>
</html>Because the variables live on :root, every rule below it can read them, and changing one value in a single place re-themes the whole page.
Styling the root element itself
:root can also carry ordinary declarations. Here it sets the page background, and body adds an inset block so you can see the root element behind it:
<!DOCTYPE html>
<html>
<head>
<style>
:root {
background-color: #8ebf42;
padding: 2em;
}
body {
background-color: #eee;
padding: 1.5em;
}
</style>
</head>
<body>
<h2>:root selector example</h2>
<p>Lorem ipsum is simply dummy text</p>
</body>
</html>Combining :root with other selectors
:root chains with pseudo-elements such as ::after and with other pseudo-classes such as :hover. A handy pattern is :root:hover, which lets a hover anywhere on the page change a variable and cascade the new value everywhere:
<!DOCTYPE html>
<html>
<head>
<style>
:root {
--accent: tomato;
}
:root:hover {
--accent: rebeccapurple;
}
h2 {
color: var(--accent);
}
</style>
</head>
<body>
<h2>Hover anywhere to recolor this heading</h2>
</body>
</html>Gotchas
:rootis not*.:rootselects only the one top-level element, while the universal selector*selects every element. Use:rootfor document-level settings, not to "select everything."- Specificity matters. Because
:rootoutrankshtml, a laterhtml { ... }rule will not override a:rootrule on the same property — a common surprise when you mix the two. - It's still just one element. Styling
:rootstyles<html>; it does not automatically style<body>or anything inside it.
Browser support and spec
:root is supported in every modern browser. It is defined in the CSS Selectors specification: