Reminder that @scope and HTML style blocks are a potent combo

There are so many different tools for writing scoped CSS with very different takes on how to go about it. Sometimes it’s only a sub-feature of a tool that does other things. But it’s generally thought of as a concept the requires tooling to accomplish.

Have you ever written a React component that imported scoped styles, perhaps as a CSS module?

import styles from "./MyComponent.module.css";Code language: JavaScript (javascript)

Or used a Styled Component to push some styles onto a component you’re already defining?

const Button = styled.button``Code language: JavaScript (javascript)

Maybe your Vue components used <style scoped> blocks within them like you can do with Vue Single File Components out of the box?

<template>
  <button>Submit</button>
</template>

<style scoped>
  button {
    border: 3px solid green;
  }
</script>Code language: HTML, XML (xml)

Despite the seemingly widely-applicable button selector above, the styles will actually be tightly scoped to the button you see in the template after processing.

Or maybe you use Tailwind to apply styling classes directly to elements and like it partially because you don’t have to “name anything”.

There are a lot of solutions like this out there in the land of building websites. I’m pretty convinced myself that scoped CSS is a good idea:

  • There is little to worry about. Styles won’t leak out and have unintended consequences.
  • It’s possible to do efficient things like not load the styles for components that don’t appear on a particular page at the time of loading.
  • When a component retires, so do it’s styles.
  • Styles are often “co-located” with the component, meaning there is a logical obvious connection between markup and styles.

I’m here to tell you: you can do all this stuff with just HTML and CSS.

And I’m not even talking about Web Components or anything particularly controversial or limiting. Vanilla HTML and CSS.

What you do is dump a <style> block in the HTML at the point you want the styles scoped. Just like this:

<main>

   <div>
     <p>Dum de dum de dum.<p>
   </div>

   <div>
     <p>Hi ho here we go.</p>

     <style>
      @scope { /* Scope is the <div> above, as this is a direct child. */
        :scope { /* This selects the <div> */
          border: 1px solid red;
          
          /* I can use CSS nesting in here, ensuring *everything* is safely scoped */
          p {
            color: red;
          }
        }
      }
     </style>
   </div>

</main>Code language: HTML, XML (xml)

Here’s an example of using it where one of these three <article>s has a scoped styles variation:

I’m using the scoped styles as a “variation” there, but the whole block of styles of that component could be used like that whether it is a variation or not. It’s a way to apply styling only to a particular branch of the ol’ DOM tree. No tooling required. Any way you produce components that end up in the DOM could be done this way, from basic HTML includes to fancy framework components.

Why isn’t this being used much?

Well, it’s the Firefox support mostly I think. Firefox just straight up doesn’t support it at the time of this writing. I’d say this is a strong candidate for Interop 2025. It looked like it was tried for in 2024 but maybe it was too new or something. But maybe Interop isn’t needed as it appears as if it’s being actively worked on, so maybe it won’t be long, dunno.

Once Firebox support is there, I could imagine this as being highly used as a way to accomplish scoped styles for components. It doesn’t require any tooling or have any limitations on what CSS you can use. I would think that would appeal to any existing CSS scoping tool as it would require them to do much less work and work faster.

CSS @scope can do more things, but this particular feature is my favorite and likely to have the biggest impact over time.

Wanna learn CSS from a course?

5 responses to “Reminder that @scope and HTML style blocks are a potent combo”

  1. Zach Saucier Zach Saucier says:

    Wouldn’t this be not so great in terms of file size since it requires the style tag and CSS be included every time this “component” is used? So for an element that only appears once or items above the fold that you want to render immediately this technique would be great but for most components it would be more file size intensive, right?

    • Chris Coyier says:

      HTML file size and DOM size yeah… I could see that being a tradeoff to deal with there, possibly one that makes this a stow stopper is some situations. The caching of a CSS file is a beautiful thing.

      I feel like if we’re comparing it to slapping styles into runtime JavaScript though, this has still gotta win right?

    • Rodrigo says:

      For the test i’ve done you can just use and have it load the css only once and as a bonus you only have to make changes in one place.

  2. Ben says:

    This sounds pretty interesting but I realise that we kind of have at least part of this since the beginning of CSS, and forgot it maybe?
    If we simply put a style attribute in the <div />, our border applies as well. And anything that would cascade down.
    It doesn’t cover tag selectors or classes of course but defining those “local” styles as overrides under a specific class that we would add to the initial <div /> would also do the trick.
    Seems like a solution to a non-existing problem to me.

  3. Coop Coding says:

    Also one small caveat is that vscode doesn’t currently support intellisense for it: https://github.com/microsoft/vscode-css-languageservice/issues/406

Leave a Reply

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

Did you know?

Frontend Masters Donates to open source projects. $313,806 contributed to date.