htmlcsscss-selectorsfont-sizecss-specificity

Why font-size defined at :root is overriden by user agent stylesheet? If it's intended to be, then how is th snippet supposed to work?


My understanding is that the CSS in the following snippet is for having font-size vary gradually with the viewport, a possiple building block to accomplish responsive design:

:root {
  font-size: calc(.6em + 1vw);
}
<html lang="it">
  <body>
    <h1>Title</h1>
    text
  </body>
</html>

The devtools, however, show me that font-size: calc(.6em + 1vw); is overridden (and show like this: font-size: calc(.6em + 1vw);) by the following ruleset of the user agent stylesheet

h1 {
    font-size: 2em;
    /* and other stuff */
}

Why does this happen?

The :root { font-size: calc(.6em + 1vw); } ruleset is not my invention, so it ought to work, and I think I'm just misusing/misunderstanding it.

My understanding is that the :root selector targets the same object as the html selector, but with class specificity rather than tag specificity. Given this, I'd expect that the user agent stylesheet's h1 {} ruleset can't override it.


Solution

  • This is because following style

    :root { font-size: calc(.6em + 1vw); }
    

    in the case of h1, is just an inherited style. Any styles applied directly to the element will override inherited styles, which is exactly what the user agent is doing with h1 { font-size: 2em;}

    If you want to inherit the root style, you can explicitly set:

    h1 {
       font-size: inherit; 
    }
    

    In this case both you and the user agent apply the style directly and yours will win since it has same specificity and it's loaded after the other.
    But the problem with this approach is that if <body>or any closest parent has an explicit font-size it'll inherit that instead of root.

    Imo this whole situation is much better handled by a CSS variable.

    :root {
      --font-size: calc(.6em + 1vw);
    }
    
    h1 {
      font-size: var(--font-size);
    }
    <html lang="it">
    
    <body>
      <h1>Title</h1>
      text
    </body>
    
    </html>