Select html in CSS: Senior Dev Guide to Root Selectors

We need to talk about CSS architecture. For some reason, the standard advice for years has been to just throw everything into the :root selector and hope for the best. While it works, there are actually several ways to select html in CSS, and choosing the wrong one can lead to specificity nightmares or unnecessary refactoring later down the road.

As a senior developer who has spent the last decade cleaning up “legacy” CSS in custom WordPress themes, I’ve seen developers struggle with selectors that are either too weak or so strong they require !important to override. Let’s look at how to handle the root element properly.

1. The Basic html Selector

The most straightforward way is to use the element selector. It has a specificity of 0-0-1. It’s low-impact, easy to read, and works everywhere.

html {
  background-color: #f0f0f0;
  scroll-behavior: smooth;
}

2. The :root Pseudo-Class

According to the MDN documentation, the :root pseudo-class represents the <html> element in an HTML document. However, it has a specificity of 0-1-0. This makes it stronger than the html selector.

This is where we usually declare our global CSS variables. Because :root is a pseudo-class, it will override styles defined in a simple html block elsewhere. I’ve seen this cause massive confusion in large-scale projects where “reset” styles and “variable” styles start fighting each other.

:root {
  --primary-color: #007cba;
  --main-font: 'Inter', sans-serif;
}

3. The Modern :scope Selector

If you’re keeping up with the W3C Selectors Level 4 specifications, you’ve likely seen :scope. When used at the top level of a stylesheet, it matches the <html> element.

I personally prefer :scope for global variables because it makes the intent clear: these variables belong to the global scope. In practice, however, the behavior is identical to :root in a browser environment.

If you’re interested in more advanced scoping, you should check out my guide on using CSS @scope to avoid heavy abstractions in your WordPress projects.

4. The Nesting Ampersand (&)

With native CSS nesting now baseline, using & at the top level is another way to select html in CSS. When & isn’t nested inside a parent block, it defaults to the scope root (which is the HTML element). It’s a bit of a “gotcha” that catches many junior devs off guard when they first move from SCSS to native CSS nesting.

5. Quirky Structural Selectors

Then we have the “war story” selectors—the things we do when the markup is out of our control or we’re feeling particularly clever. For instance, :has(body) or :has(head) can only ever select the root element. Is it practical? Absolutely not. Is it a fun technical flex? Maybe.

One of my favorite useless-but-fascinating selectors is the “bird” selector:

:not(* > *) {
  /* This selects the root because it's the only element 
     that is NOT a child of something else. */
}

This structural trick works because the <html> element is the only node that doesn’t have a parent. Just because you can do this doesn’t mean you should ship it to production. Your coworkers (and your future self) will thank you for using :root instead.

Speaking of specificity, managing it in WordPress can be a nightmare. I wrote a piece on how the WordPress CSS specificity fix works if you’re struggling with block styles overriding your custom theme.

Look, if this Select html in CSS stuff is eating up your dev hours, let me handle it. I’ve been wrestling with WordPress since the 4.x days.

The Final Verdict

Stick to :root for your variables and html for your base typography and background resets. Avoid the structural hacks unless you’re writing a specialized CSS scraper or dealing with a truly broken document tree. Keep your specificity low and your architecture predictable—that’s how you ship stable, high-performance themes without losing your mind.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.

Leave a Comment