7.2 KiB
Isolate CSS styles to individual pages, views, and components to reduce or avoid:
- Dependencies on global styles that can be challenging to maintain.
- Style conflicts in nested content.
To add a scoped CSS file for a page or view, place the CSS styles in a companion .cshtml.css
file matching the name of the .cshtml
file. In the following example, an Index.cshtml.css
file supplies CSS styles that are only applied to the Index.cshtml
page or view.
Pages/Index.cshtml.css
(Razor Pages) or Views/Index.cshtml.css
(MVC):
h1 {
color: red;
}
CSS isolation occurs at build time. The framework rewrites CSS selectors to match markup rendered by the app's pages or views. The rewritten CSS styles are bundled and produced as a static asset, {APP ASSEMBLY}.styles.css
. The placeholder {APP ASSEMBLY}
is the assembly name of the project. A link to the bundled CSS styles is placed in the app's layout.
In the <head>
content of the app's Pages/Shared/_Layout.cshtml
(Razor Pages) or Views/Shared/_Layout.cshtml
(MVC), add or confirm the presence of the link to the bundled CSS styles:
<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />
In the following example, the app's assembly name is WebApp
:
<link rel="stylesheet" href="WebApp.styles.css" />
The styles defined in a scoped CSS file are only applied to the rendered output of the matching file. In the preceding example, any h1
CSS declarations defined elsewhere in the app don't conflict with the Index
's heading style. CSS style cascading and inheritance rules remain in effect for scoped CSS files. For example, styles applied directly to an <h1>
element in the Index.cshtml
file override the scoped CSS file's styles in Index.cshtml.css
.
[!NOTE] In order to guarantee CSS style isolation when bundling occurs, importing CSS in Razor code blocks isn't supported.
CSS isolation only applies to HTML elements. CSS isolation isn't supported for Tag Helpers.
Within the bundled CSS file, each page, view, or Razor component is associated with a scope identifier in the format b-{STRING}
, where the {STRING}
placeholder is a ten-character string generated by the framework. The following example provides the style for the preceding <h1>
element in the Index
page of a Razor Pages app:
/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
color: red;
}
In the Index
page where the CSS style is applied from the bundled file, the scope identifier is appended as an HTML attribute:
<h1 b-3xxtam6d07>
The identifier is unique to an app. At build time, a project bundle is created with the convention {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css
, where the placeholder {STATIC WEB ASSETS BASE PATH}
is the static web assets base path.
If other projects are utilized, such as NuGet packages or Razor class libraries, the bundled file:
- References the styles using CSS imports.
- Isn't published as a static web asset of the app that consumes the styles.
CSS preprocessor support
CSS preprocessors are useful for improving CSS development by utilizing features such as variables, nesting, modules, mixins, and inheritance. While CSS isolation doesn't natively support CSS preprocessors such as Sass or Less, integrating CSS preprocessors is seamless as long as preprocessor compilation occurs before the framework rewrites the CSS selectors during the build process. Using Visual Studio for example, configure existing preprocessor compilation as a Before Build task in the Visual Studio Task Runner Explorer.
Many third-party NuGet packages, such as AspNetCore.SassCompiler
, can compile SASS/SCSS files at the beginning of the build process before CSS isolation occurs, and no additional configuration is required.
CSS isolation configuration
CSS isolation permits configuration for some advanced scenarios, such as when there are dependencies on existing tools or workflows.
Customize scope identifier format
In this section, the {Pages|Views}
placeholder is either Pages
for Razor Pages apps or Views
for MVC apps.
By default, scope identifiers use the format b-{STRING}
, where the {STRING}
placeholder is a ten-character string generated by the framework. To customize the scope identifier format, update the project file to a desired pattern:
<ItemGroup>
<None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
In the preceding example, the CSS generated for Index.cshtml.css
changes its scope identifier from b-{STRING}
to custom-scope-identifier
.
Use scope identifiers to achieve inheritance with scoped CSS files. In the following project file example, a BaseView.cshtml.css
file contains common styles across views. A DerivedView.cshtml.css
file inherits these styles.
<ItemGroup>
<None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
<None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Use the wildcard (*
) operator to share scope identifiers across multiple files:
<ItemGroup>
<None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Change base path for static web assets
The scoped CSS file is generated at the root of the app. In the project file, use the StaticWebAssetBasePath
property to change the default path. The following example places the scoped CSS file, and the rest of the app's assets, at the _content
path:
<PropertyGroup>
<StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>
Disable automatic bundling
To opt out of how framework publishes and loads scoped files at runtime, use the DisableScopedCssBundling
property. When using this property, other tools or processes are responsible for taking the isolated CSS files from the obj
directory and publishing and loading them at runtime:
<PropertyGroup>
<DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>
Razor class library (RCL) support
When a Razor class library (RCL) provides isolated styles, the <link>
tag's href
attribute points to {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css
, where the placeholders are:
{STATIC WEB ASSET BASE PATH}
: The static web asset base path.{PACKAGE ID}
: The library's package identifier. The package identifier defaults to the project's assembly name if the package identifier isn't specified in the project file.
In the following example:
- The static web asset base path is
_content/ClassLib
. - The class library's assembly name is
ClassLib
.
Pages/Shared/_Layout.cshtml
(Razor Pages) or Views/Shared/_Layout.cshtml
(MVC):
<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">
For more information on RCLs, see the following articles:
For information on Blazor CSS isolation, see xref:blazor/components/css-isolation.