Developers are human beings…

If there’s one thing we know about human beings it’s that they’re hardwired to take the shortest route from A to B…

Which probably explains why you have a single stylesheet in your app where ALL the CSS styles go.

One stylesheet to rule them all

You’re working on your app and realise you need to tweak the CSS…

… so you go to the one place where all the styles live.

Once there you realise you need a new style but where should you put it?

I mean… you’re already in this file which has lots of other CSS styles, and creating a new one would mean naming it, and linking to it from your main HTML page.

That all sounds like work and it’s nearly lunchtime… maybe, just this once, you could add one teeny-tiny little style to the bottom of this file?

Go round this hamster wheel a few times; site.css gets bigger, new styles are chucked on the end and tweaking your styles takes longer, and longer (as does figuring out why anything looks the way it does).

.NET 5 offers a solution - CSS Isolation

Enter .NET 5 and CSS Isolation.

With CSS Isolation you can define styles for your components right there, next to the component.

All you need to do is:

  1. Create a new <component>.razor.css file
  2. Define your component’s styles in that file
  3. Get on with the rest of your day (or you know, go for lunch)

Say you want to tweak the styles for the Counter component which ships with the Blazor project templates.

With .NET 5 you can create a new Counter.razor.css file.

In there, define your styles as normal at which point Blazor will automatically wire everything up so Counter uses these styles.


h1 {
    font-size: 1.6em;
    color: red;
    font-weight: bold;
    font-style: italic;

The big win is that these styles only apply to the specific component. So you can happily set styles for generic elements like h1, confident that it will only affect this component’s h1 elements and not the other h1 elements in your application.


<h1>Regular H1 (outside of Counter component)</h1>

<Counter />

Go ::deep

By default these styles will only apply to the specific component, not child components.

For example:


    <p>Current count: @currentCount</p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

If the Counter component includes another component (CustomHeading in this example), and that component has an h1 tag:

<h1 class="heading">@ChildContent</h1>

@code {
    public RenderFragment ChildContent { get; set; } 

The style we defined in Counter.razor.css won’t apply to the h1 in CustomHeading.

However, you can make it apply using the ::deep combinator.


::deep h1 {
    font-size: 1.6em;
    color: red;
    font-weight: bold;
    font-style: italic;

Now any child components with h1 elements will take on this style as well.

How it works

When you use this feature in .NET 5 Blazor automatically gives your elements unique names/identifiers and rewrites your CSS rules to use these identifiers (at build time).

It also compiles all the various CSS styles into a file called {project_name}.styles.css.

So your HTML will end up looking something like this (when you inspect the source):

<div b-dmd9kyn336="">
    <h1 class="heading">Counter</h1>
    <!-- other markup -->

And the corresponding file can be seen in {project_name}.styles.css.

/* /Pages/Counter.razor.rz.scp.css */
[b-dmd9kyn336] h1 {
    font-size: 1.6em;
    color: red;
    font-weight: bold;
    font-style: italic;

If we omit the ::deep combinator from our example we get slightly different CSS in {project_name}.styles.css.

/* /Pages/Counter.razor.rz.scp.css */
h1[b-dmd9kyn336] {
    font-size: 1.6em;
    color: red;
    font-weight: bold;
    font-style: italic;

This shows the clear difference between using or not using ::deep.

In summary

Once you start thinking in terms of components it follows you’ll want fine-grained control of each component’s appearance using CSS.

CSS Isolation in .NET 5 makes this much easier and keeps the CSS close to the markup it affects (avoiding the problem of everything getting thrown into one big stylesheet, making maintenance much more difficult).

Build better ASP.NET web applications, faster

I email every week with hints, tips and advice on how to push through all the noise to get your ASP.NET applications built.

Drop your email in the box below and I'll send new articles straight to your inbox.

I respect your email privacy. No spam, unsubscribe anytime with one click.


Next up

Will .NET 6 fix Blazor Prerendering?
Prerendering eradicates Blazor WASM’s initial load time and .NET 6 promises to address its one key limitation
Persisting your users preferences using Blazor and Local Storage
Now your app supports dark mode, let’s make sure your visitors only have to choose it once (or ideally, not at all)
Dark mode for your web applications (using Blazor and Tailwind CSS)
Eyestrain is a real problem; help your users by adapting your site to their dark mode preferences