Styling isn't just about making things look good - it's about creating maintainable and reusable UI components. Blazor offers several ways to apply CSS, each suited for different needs and scenarios. In this tutorial, you will explore:
In Blazor, you can style components in several ways, depending on your needs:
app.css
.<style>
tag..css
file and linked to the component.style
attribute, useful for quick or dynamic styling.CSS class name pollution occurs when the same class name is used in multiple parts of an app, but with different styling intentions. For example, you might define a .card
class for one component, only to find that another part of the app already uses .card
with different styles. As a result, your styles get overridden or mixed, creating bugs that are hard to trace.
This issue forces developers to come up with overly specific or redundant class names - like .card-product
, .card-user
, and so on - just to avoid conflict.
Blazor addresses this issue through CSS isolation, a feature that scopes styles to specific components. When using scoped styles with .razor.css
files, Blazor rewrites CSS selectors at build time to include a unique scope identifier, such as .card[b-tjvd9khfp8]
. This ensures that the .warning
class in one component does not affect another. Even if other components use the same class name, the styles won’t conflict. This keeps your CSS cleaner, safer, and easier to manage in large applications.
In Blazor, global styles are CSS rules that apply to the entire application. They’re usually written in a shared file like app.css
and included via index.html
.
Global styles are helpful for defining consistent visual rules across your app - like base font settings, color themes, spacing, and common layouts. For example:
body { font-family: Arial, sans-serif; }
This rule will apply to every component unless specifically overridden. Global styles are perfect for shared UI elements such as headers, footers, buttons, or utility classes. However, since they are not scoped to any single component, they can unintentionally affect other parts of your app - a problem known as CSS class name pollution. As your app grows, this can make debugging styles more difficult, especially when class names collide.
We have mentioned the CSS class name pollution problem above and briefly noted that Blazor can resolve this issue gracefully with scoped styles.
Delving deeper into the technology that helps Blazor achieve this, we can see that it uses the Attribute selectors technique behind the scenes.
Blazor generates a unique attribute tag along with the CSS class name on the fly. For example, with the following code in your Razor file:
<span class="scoped"> The "scoped" CSS class is isolated to this component. Even if another component defines a class with the same name, it won’t interfere with or override the styles used here. </span>
And the CSS in your .razor.css
file:
.scoped { color: blue; }
Blazor then compiles it into something like this:
<span class="scoped b-tjvd9khfp8"> ... </span>
.scoped[b-tjvd9khfp8] { color: blue; }
index.html
. In some projects, you might find the line for scoped CSS commented out. Look for a line like this in your index.html
:<link href="ComponentStyling.styles.css" rel="stylesheet" />
ScopedComponentExample.razor
, create a file named ScopedComponentExample.razor.css
. Place all the CSS rules you want scoped to that component inside this file.Scoped CSS is designed to prevent unintended overrides, not to completely lock down styles. Developers can still override scoped styles when necessary.
Suppose you are using ScopedComponentExample
inside another component called OverridingScopedComponentExample
, and you want the inner component to use different styles.
OverridingScopedComponentExample
. Name it OverridingScopedComponentExample.razor.css
, and place it in the same folder as the component.::deep
, ending with the scoped class you want to override. For example:.override ::deep .scoped { color: yellow; background-color: red; }
Here:
.override
is the outer selector.::deep
is the required syntax for overriding styles of nested components..scoped
is the scoped CSS class you want to override.<div class="override"> <ScopedComponentExample /> </div>
While putting CSS in app.css
or creating a scoped CSS file is better for long-term maintenance, sometimes testing things out during development requires a simpler approach. Internal styles are perfect for this scenario because they allow you to write minimal CSS directly alongside your component and remove it quickly when no longer needed.
Internal styles work by placing a <style>
block directly inside your component, next to the elements it affects. For example:
<span class="internal-style">Hello Blazor School!</span> <style> .internal-style { color: yellow; } </style>
This approach is quick and requires no additional boilerplate. However, it comes with notable disadvantages and should generally only be used in a development environment:
External styles are a common technique that can help reduce the initial loading size of a website by grouping related CSS into a separate file and fetching it only when the component is rendered. The trade-off is a potential layout shift when the CSS file is being loaded.
In the component, you include a <link>
tag that points to the external CSS file. For example:
<link href="/css/external.css" rel="stylesheet" /> <span class="external-style">Hello Blazor School!</span>
This technique offers several advantages:
However, developers should use this technique carefully, as it comes with drawbacks:
<link>
tags may be generated when a component is rendered multiple times.When you need to apply something dynamic - such as changing text color based on a user's selection - the best approach is often to use inline styles. This technique applies styles directly to an element, giving them the highest priority.
For example, you can set the text color for a specific paragraph like this:
<span style="color: green">Hello Blazor School!</span>
Inline styles can also be useful for quick testing, similar to internal styles. However, they come with significant drawbacks: