CSS isolation in Blazor

 
 
  • Gérald Barré

When creating a Blazor application or library, you'll create many components. A component can be used by other components. By default, the CSS of the site applies to the HTML generated by your component. There are some cases where you want to isolate the style of a component. Blazor now provides CSS isolation. This post explains how to use it and how it works!

#How to use CSS isolation in Blazor

Let's create 2 basic components:

Razor
<div>
    <h1>Component1 - h1</h1>

    <Component2 />
</div>
Razor
<h1>Component2 - h1</h1>

To create specific component CSS, you need to create a CSS file with the name of the component suffixed by .css:

CSS
h1 {
    color: red;
}

You can see that the h1 element of the first component is red because of CSS isolation. Other h1s use the global CSS.

In the previous example, the second component doesn't use the CSS of the parent component. If you want to change the style of all descendant components, you can use the ::deep pseudo-selector.

CSS
::deep h1 {
    color: red;
}

#How CSS isolation works

When you use CSS isolation, Blazor generates a new CSS file named _framework/scoped.styles.css that contains the style of all scoped CSS files.

In this file, you can see that the compiler has rewritten all rules with a cryptic attribute selector. For our component, it is [b-a92ooaz332]. This name is automatically generated per component.

By adding the attribute selector, the specificity of the selector increases, so can override the global style. Also, it only applies to the elements in the component because only the element in this component has this attribute.

When generating HTML, the component emits the same attribute as the one in the CSS file for all HTML elements.

If you use the ::deep pseudo-selector, the emitted HTML is the same, but the CSS file is slightly different. The selector is prefixed by the attribute, so it matches the whole hierarchy:

The way the selector is generated for ::deep doesn't match the elements at the root of the component. Indeed, it only matches the descendant of an element having the generated attribute. Therefore, the elements at the root of the component are not matched by this selector.

HTML
<h1 b-a92ooaz332>Not styled by scoped CSS with ::deep</h1> <!-- [b-a92ooaz332] h1 doesn't match this element -->
<div b-a92ooaz332>
    <h1 b-a92ooaz332>Styled by scoped CSS</h1>
</div>

There are 2 ways to workaround this issue:

  • Use 2 selectors:

    CSS
    h1, ::deep h1 { /* Applies to current component and any descendant component */
        color: red;
    }
  • Wrap the component content with a div:

    HTML
    <div>
        <h1>Not styled by scoped CSS with ::deep</h1>
    </div>

Note that there are some CSS rewriting bugs in the current preview version. They should be fixed for the release version in November. If you encounter any issue, you should open an issue.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub