Special Offer: My C#/.NET Bootcamp Course is out now. Get 10% OFF using the code FRIENDS10.

This video is part of The FREE Blazor Crash Course. In this crash course, we build an actual Blazor WebAssembly application based on .NET 5.

Table of Content

  1. The FREE Blazor Crash Course – Getting Started
  2. Blazor Form Component & Validation
  3. Blazor API Handling
  4. Blazor Modal Dialog Component
  5. Blazor CSS Handling (this article)
  6. Static Images
  7. Building a Dashboard
  8. End-to-End Testing using SpecFlow

In this video, we will learn about CSS handling for Blazor applications. We will discuss the difference between local and global CSS definitions and how CSS isolation makes the developer’s life easier.

 

This time, we won’t implement new components for our FinanceMentor application but will make the existing components look better.

How Does CSS Work in Blazor?

Let’s start by looking at how CSS works in Blazor. First of all, it’s important to understand that Blazor uses standard CSS like every other web framework. Blazor also supports every CSS property that is supported by the browser.

If you followed along as we build the FinanceMentor application, you saw that we already used a lot of CSS in our project. We used Bootstrap to style our Earnings page and implement our modal dialog component in previous videos.

Let’s open the NavMenu component and take a closer look at how we use CSS to make the menu look great.

Using Bootstrap CSS Definitions

On the first line, for example, we use the top-row class as well as a few navbar-specific classes and padding-left of 4 units. All those classes are defined in Bootstrap. But how does it all work behind the scenes?

If I do a global search for the “.navbar” class, we get a result in the boostrap.min.css file. Let’s open the file. This file is part of the wwwroot folder. The content of the wwwroot folder gets exported as it is when we build the application. Every file in this folder will be available for the browser when the application runs on a server. Let’s rebuild the application and open Windows Explorer.

As you can see, we have a wwwroot folder in the Client project folder. When I open it, we can see the css folder we also saw in the Solution Explorer. In the css folder, I open the bootstrap folder. As you can see, there is the bootstrap.min.css file we opened in Visual Studio before.

Blazor: Minified CSS files in Windows Explorer

Blazor: Minified CSS files in Windows Explorer

Now we know that the “.navbar” class is defined in the bootstrap.min.css file, and we know that the wwwroot folder contains the file. But how does the application load the file?

How Blazor Loads CSS Files

Let’s open the index.html file, which is also stored in the wwwroot folder.

If you are familiar with other web development frameworks like React or Angular, this index.html definition should not surprise you. We have a head section that defines the viewport of the application, sets the base path, and, most importantly, defines a link statement to load every individual CSS file we use in the Blazor application.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>FinanceMentor</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="FinanceMentor.Client.styles.css" rel="stylesheet" />
</head>

<body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss"></a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

Let’s go through those definitions one-by-one.

The first definition includes the minified Boostrap CSS. We already talked about it before.

The second definition includes a global stylesheet for our application. We haven’t talked about it yet. Let’s change that and open the file. As you can see, we have a few global definitions like the font family or the link color.

@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #0366d6;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.content {
    padding-top: 1.1rem;
}

// Code omitted

Let’s go back to the index.html file.

The third definition is different. We have an href definition that does not match a physical file in the wwwroot folder. This is a Blazor specific feature that allows us to use CSS isolation.

How CSS Isolation Works in Blazor

Let’s learn about CSS Isolation in Blazor. The statement you can see includes a file that gets generated during the build process.

Let’s take a look at the file that gets generated when we build the Blazor application. We open the Windows Explorer at the following path: Client\obj\Debug\net5.0\scopedcss\bundle.

Bundled CSS isolation file in Blazor applications.

Bundled CSS isolation file in Blazor applications.

And there, you can see the FinanceMentor.Client.styles.css file. Let’s open the file.

/* /Shared/MainLayout.razor.rz.scp.css */
.page[b-7kgtpv30g8] {
    position: relative;
    display: flex;
    flex-direction: column;
}

.main[b-7kgtpv30g8] {
    flex: 1;
}

.sidebar[b-7kgtpv30g8] {
    background-image: linear-gradient(180deg, #71818e 0%, #122d42 70%);
}

.top-row[b-7kgtpv30g8] {
    background-color: #f7f7f7;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-end;
    height: 80px;
    display: flex;
    align-items: center;
}

// Code omitted

As you can see, every CSS selector contains a generated part at the end. The generated ID is the same for every CSS definition that belongs to the same Blazor component. In the comment on the first line, you can see that the statements below belong to the MainLayout component in the Shared folder.

If we scroll down, we can see another comment before the CSS definitions of the NavMenu component follow.

/* /Shared/NavMenu.razor.rz.scp.css */
.navbar-toggler[b-4rg7dnf475] {
    background-color: rgba(255, 255, 255, 0.1);
}

.top-row[b-4rg7dnf475] {
    height: 3.5rem;
    background-color: rgba(0,0,0,0.4);
}

.navbar-brand[b-4rg7dnf475] {
    font-size: 1.1rem;
}

.oi[b-4rg7dnf475] {
    width: 2rem;
    font-size: 1.1rem;
    vertical-align: text-top;
    top: -2px;
}

.nav-item[b-4rg7dnf475] {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}

// Code omitted

The main benefit of using CSS isolation is that we can use short and descriptive names for our CSS classes and don’t have to be afraid of any name clashes across our application or any external CSS definitions like Boostrap.

How to Use CSS Isolation in Blazor

Now that we know how a dynamically generated Blazor CSS file looks like and how it is referenced in the index.html, let’s talk about how we can use CSS isolation for our components.

First, let’s take a look at the NavMenu component. If we look at the component in the Solution Explorer, we can expand the item and find a NavMenu.razor.css file.

If we name a CSS file the same as the component and end it with .razor.css, we enable the CSS isolation feature using the naming convention.

.navbar-toggler {
    background-color: rgba(255, 255, 255, 0.1);
}

.top-row {
    height: 3.5rem;
    background-color: rgba(0,0,0,0.4);
}

.navbar-brand {
    font-size: 1.1rem;
}

.oi {
    width: 2rem;
    font-size: 1.1rem;
    vertical-align: text-top;
    top: -2px;
}

.nav-item {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}

// Code omitted

As you can see, there is no unique Id part of the selector definitions in this file. We can have short and descriptive names and use them in the component. Blazor generates the Ids and puts all component definitions into a single file during build time.

Changing the Look of the Sidebar

We talked a lot about CSS. Let’s open the MainLayout.razor.css file and change our sidebar colors to reflect the seriousness of our FinanceMentor application better.

In the sidebar selection definition, let’s change the linear-gradient.

.sidebar {
    background-image: linear-gradient(180deg, #71818e 0%, #122d42 70%);
}

Now, let’s build and start the application.

As you can see, the sidebar now has different colors.

Let’s open the developer console and navigate to the Network tab. Select CSS to filter the requests to show only CSS files. Now press CTRL+F5 to reload the page without caching.

Now let’s click on the FinanceMentor.Client.styles.css file. And there you can see the CSS definition we just changed.

Bundled CSS File in the Developer Tools shows how CSS Isolation works

Bundled CSS File in the Developer Tools shows how CSS Isolation works

We can also customize the identifier format in the project file. However, in most projects, the default identifiers will be good enough.

CSS Preprocessor Support

If you are an experienced web developer, you might have the question if Blazor supports Less or Sass as a CSS preprocessor. The answer is yes and no. Blazor does not support it, but it can handle it if the preprocessing happens before Blazor executes CSS Isolation.

You could use a Before Build task in Visual Studio, or you could use third-party packages such as Delegate.SassBuilder. However, CSS preprocessing is an advanced topic we will not explore within this Blazor Crash Course.

Local vs. Global CSS Definitions

We talked a lot about CSS Isolation and local CSS definitions besides our components. It can be helpful to have all the required definitions close to the component in separated files.

However, if you want to share styles across components, you can define them in the app.css file or in a custom CSS file that you include in the wwwroot folder and reference in the index.html file.

The important thing to keep in mind is that CSS Isolation only applies to local CSS definitions defined in files named similarly to its component files. Global CSS files are neither bundled nor altered with a unique identifier.

Housekeeping

After we learned so much about handling CSS, let’s improve our application’s appearance.

Let’s start by setting the height of the app navbar in the MainLayout component. We use CSS isolation. In the CSS file, we change the height definition of the top-row class to 80 pixels.

.top-row {
    background-color: #f7f7f7;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-end;
    height: 80px;
    display: flex;
    align-items: center;
}

Next, we want to remove all the code from the project template that we do not need in the FinanceMentor application.

In the Solution Explorer, we remove the Counter component and the FetchData component. Next, we open the NavMenu component and remove the links to the removed components.

In the Shared project, we can also remove the WeatherForecast class. And in the Server project, we remove the WeatherForecastController class.

Now let’s start the application to see how it looks.

FinanceMentor: Styled NavBar using CSS Isolation

FinanceMentor: Styled NavBar using CSS Isolation

Great, we did some housekeeping, and we improved the styling of our application.

Summary

This video is the fifth part of the FREE Blazor Crash Course.

  • You learned how Blazor applications load CSS files.
  • You learned the difference between local and global CSS definitions.
  • You learned how CSS Isolation works and what naming convention enables it for Blazor components.

What’s Next?

In the next video of this series, we will look at how to use static images in Blazor applications. We will use it to add a logo to our application.

Tell me in the comments below if you like CSS isolation or prefer global styles when building web applications.

Thanks for watching, don’t forget to subscribe, so you don’t miss the next part of this FREE Blazor Crash Course, and see you in the next video.

 

 

Claudio Bernasconi

I'm an enthusiastic Software Engineer with a passion for teaching .NET development on YouTube, writing articles about my journey on my blog, and making people smile.