ASP.NET Core Blazor-CSS-Isolation

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der ASP.NET Core 8.0-Version dieses Artikels.

Von Dave Brock

In diesem Artikel wird erläutert, wie Sie mit der CSS-Isolation den Bereich von CSS auf Razor-Komponenten beschränken können, um den CSS-Code zu vereinfachen und Konflikte mit anderen Komponenten oder Bibliotheken zu vermeiden.

Isolieren Sie zur Reduzierung oder Vermeidung CSS-Formatvorlagen auf einzelne Seiten, Ansichten und Komponenten:

  • Abhängigkeiten von globalen Stilen, die eine Herausforderung darstellen können
  • Formatkonflikte in geschachtelten Inhalten

Aktivieren der CSS-Isolation

Damit Sie komponentenspezifische Stile definieren können, erstellen Sie eine Datei .razor.css, die mit dem Namen der .razor-Datei für die Komponente im selben Ordner übereinstimmt. Die Datei .razor.css ist eine bereichsbezogene CSS-Datei.

Erstellen Sie für eine Example-Komponente in einer Example.razor-Datei eine Datei mit dem Namen Example.razor.css. Die Example.razor.css-Datei muss sich im gleichen Ordner befinden wie die Example-Komponente (Example.razor). Beim Example-Basisnamen der Datei wird die Groß-/Kleinschreibung nicht beachtet.

Example.razor:

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css:

h1 { 
    color: brown;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
}

Die in Example.razor.css definierten Stile werden nur auf die gerenderte Ausgabe der Example-Komponente angewandt. Die CSS-Isolation wird auf HTML-Elemente in der entsprechenden Razor-Datei angewandt. h1-CSS-Deklarationen, die an anderer Stelle in der App definiert sind, verursachen keine Konflikte mit den Stilen der Example-Komponente.

Hinweis

Damit die Stilisolation auch bei der Bündelung gewährleistet ist, wird das Importieren von CSS in Razor-Codeblöcken nicht unterstützt.

Bündelung mit CSS-Isolation

Die CSS-Isolation erfolgt zum Zeitpunkt der Erstellung. Blazor schreibt CSS-Selektoren um, sodass diese dem Markup entsprechen, das von der Komponente gerendert wird. Die umgeschriebenen CSS-Formatvorlagen werden gebündelt und als statisches Objekt erzeugt. Auf das Stylesheet wird innerhalb des <head>-Tags verwiesen (Speicherort des <head>-Inhalts). Das folgende <link>-Element wird standardmäßig zu einer App hinzugefügt, die anhand der Blazor-Projektvorlagen erstellt wurde. Dabei entspricht der Platzhalter {ASSEMBLY NAME} dem Assemblynamen des Projekts:

<link href="{ASSEMBLY NAME}.styles.css" rel="stylesheet">

Das folgende Beispiel stammt aus einer gehosteten Blazor WebAssemblyClient-App. Der Assemblyname der App lautet BlazorSample.Client, und <link> wird von der Blazor WebAssembly-Projektvorlage hinzugefügt, wenn das Projekt mit der Option „Hosted“ erstellt wird (Option -ho|--hosted bei der .NET-CLI oder Kontrollkästchen ASP.NET Core, gehostet in Visual Studio):

<link href="BlazorSample.Client.styles.css" rel="stylesheet">

Innerhalb der gebündelten Datei ist jede Komponente einem Bereichsbezeichner zugeordnet. Für jede formatierte Komponente wird ein HTML-Attribut mit dem Format b-{STRING} angefügt, wobei der Platzhalter {STRING} eine vom Framework generierte Zeichenfolge mit zehn Zeichen ist. Der Bezeichner ist für jede Anwendung eindeutig. In der gerenderten Counter-Komponente fügt Blazor einen Bereichsbezeichner an das h1-Element an:

<h1 b-3xxtam6d07>

Die Datei {ASSEMBLY NAME}.styles.css verwendet den Bereichsbezeichner, um eine Stildeklaration mit Ihrer Komponente zu gruppieren. Im folgenden Beispiel wird der Stil für das vorherige <h1>-Element bereitstellt:

/* /Components/Pages/Counter.razor.rz.scp.css */
h1[b-3xxtam6d07] {
    color: brown;
}

Zur Buildzeit wird ein Projektpaket mit der Konvention obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css erstellt, wobei die Platzhalter die folgenden sind:

  • {CONFIGURATION}: Die Buildkonfiguration der App (z. B. Debug, Release)
  • {TARGET FRAMEWORK}: Das Zielframework (z. B. net6.0)
  • {ASSEMBLY NAME}: Der Assemblyname der App (z. B. BlazorSample)

Unterstützung für untergeordnete Komponenten

Standardmäßig gilt die CSS-Isolation nur für die Komponente, die Sie dem Format {COMPONENT NAME}.razor.css zuordnen, wobei der Platzhalter {COMPONENT NAME} in der Regel der Komponentenname ist. Verwenden Sie zum Anwenden von Änderungen auf eine untergeordnete Komponente das ::deep-Pseudoelement für alle Nachfolgerelemente in der Datei .razor.css der übergeordneten Komponente. Das ::deep-Pseudoelement wählt Elemente aus, die Nachfolger des generierten Bereichsbezeichners eines Elements sind.

Das folgende Beispiel zeigt die übergeordnete Komponente Parent, die eine untergeordnete Komponente namens Child hat.

Parent.razor:

@page "/parent"

<div>
    <h1>Parent component</h1>

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

Aktualisieren Sie die h1-Deklaration in Parent.razor.css mit dem ::deep-Pseudoelement, um anzugeben, dass die Style-Deklaration h1 auf die übergeordnete Komponente und deren untergeordnete Komponenten angewandt werden muss.

Parent.razor.css:

::deep h1 { 
    color: red;
}

Der h1-Stil gilt jetzt für die Komponenten Parent und Child, ohne dass eine separate CSS-Datei für die untergeordnete Komponente erstellt werden muss.

Das ::deep-Pseudoelement funktioniert nur mit Nachfolgerelementen. Das folgende Markup wendet die h1-Stile wie erwartet auf Komponenten an. Der Bereichsbezeichner der übergeordneten Komponente wird auf das div-Element angewendet, damit der Browser weiß, dass Stile von der übergeordneten Komponente geerbt werden.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

Durch Ausschließen des div-Elements wird jedoch die Nachfolgerbeziehung entfernt. Im folgenden Beispiel wird der Stil nicht auf die untergeordnete Komponente angewendet.

Parent.razor:

<h1>Parent</h1>

<Child />

Das ::deep-Pseudoelement wirkt sich darauf aus, wo das Bereichsattribute auf die Regel angewendet wird. Wenn Sie eine CSS-Regel in einer CSS-Bereichsdatei definieren, wird der Bereich standardmäßig auf das äußerste rechte Element angewendet. Beispiel: div > a wird in div > a[b-{STRING}] transformiert, wobei der Platzhalter {STRING} eine zehnstellige Zeichenfolge ist, die vom Framework generiert wird (z. B. b-3xxtam6d07). Wenn die Regel stattdessen auf einen anderen Selektor angewendet werden soll, ermöglicht das ::deep-Pseudoelement dies. Beispielsweise wird div ::deep > a in div[b-{STRING}] > a transformiert (z. B. div[b-3xxtam6d07] > a).

Mit der Möglichkeit, das ::deep-Pseudoelement an ein beliebiges HTML-Element anzufügen, können Sie bereichsbezogene CSS-Formatvorlagen erstellen, die sich auf Elemente auswirken, die von anderen Komponenten gerendert werden, wenn Sie die Struktur der gerenderten HTML-Tags bestimmen können. Im Falle einer Komponente, die ein Hyperlinktag (<a>) innerhalb einer anderen Komponente rendert, stellen Sie sicher, dass die Komponente von einer div (oder einem anderen Element) umschlossen ist, und verwenden Sie die Regel ::deep > a, um eine Formatvorlage zu erstellen, die nur auf diese Komponente angewendet wird, wenn die übergeordnete Komponente gerendert wird.

Wichtig

Die bereichsbezogene CSS-Datei gilt nur für HTML-Elemente und nicht für Razor-Komponenten oder Taghilfsprogrammen, einschließlich Elementen mit angewendetem Taghilfsprogramm, z. B. <input asp-for="..." />.

Unterstützung für CSS-Präprozessoren

CSS-Präprozessoren tragen zur Verbesserung der CSS-Entwicklung bei, indem sie Features wie Variablen, Schachtelung, Module, Mischung und Vererbung nutzen. CSS-Isolation unterstützt CSS-Präprozessoren wie Sass oder Less zwar nicht nativ, dennoch können CSS-Präprozessoren nahtlos integriert werden, sofern die Kompilierung des Präprozessors erfolgt, bevor Blazor die CSS-Selektoren während des Buildprozesses umschreibt. Konfigurieren Sie z. B. mithilfe von Visual Studio die vorhandene Präprozessorkompilierung als Aufgabe Vor Build im Aufgabenausführungs-Explorer von Visual Studio.

Viele NuGet-Pakete von Drittanbietern, z. B. AspNetCore.SassCompiler, können die SASS-/SCSS-Dateien am Anfang des Buildprozesses kompilieren, noch vor der CSS-Isolation.

Konfiguration der CSS-Isolation

Die CSS-Isolation ist so konzipiert, dass sie sofort einsatzbereit ist. Es ist aber eine Konfiguration für einige erweiterte Szenarien möglich, wenn z. B. Abhängigkeiten von vorhandenen Tools oder Workflows vorhanden sind.

Anpassen des Formats von Bereichsbezeichnern

Standardmäßig verwenden Bereichsbezeichner das Format b-{STRING}, wobei der Platzhalter {STRING} eine vom Framework generierte Zeichenfolge mit zehn Zeichen ist. Um das Format der Bereichsbezeichner anzupassen, aktualisieren Sie die Projektdatei mit dem gewünschten Muster:

<ItemGroup>
  <None Update="Components/Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Im vorherigen Beispiel ändert der für Example.razor.css generierte CSS-Code seinen Bereichsbezeichner von b-{STRING} in custom-scope-identifier.

Verwenden Sie Bereichsbezeichner, um eine Vererbung mit bereichsbezogenen CSS-Dateien zu erzielen. Im folgenden Beispiel für eine Projektdatei enthält eine BaseComponent.razor.css-Datei allgemeine Stile in Komponenten. Eine DerivedComponent.razor.css-Datei erbt diese Stile.

<ItemGroup>
  <None Update="Components/Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Components/Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Verwenden Sie den Platzhalteroperator (*), um Bereichsbezeichner für mehrere Dateien freizugeben:

<ItemGroup>
  <None Update="Components/Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Standardmäßig verwenden Bereichsbezeichner das Format b-{STRING}, wobei der Platzhalter {STRING} eine vom Framework generierte Zeichenfolge mit zehn Zeichen ist. Um das Format der Bereichsbezeichner anzupassen, aktualisieren Sie die Projektdatei mit dem gewünschten Muster:

<ItemGroup>
  <None Update="Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Im vorherigen Beispiel ändert der für Example.razor.css generierte CSS-Code seinen Bereichsbezeichner von b-{STRING} in custom-scope-identifier.

Verwenden Sie Bereichsbezeichner, um eine Vererbung mit bereichsbezogenen CSS-Dateien zu erzielen. Im folgenden Beispiel für eine Projektdatei enthält eine BaseComponent.razor.css-Datei allgemeine Stile in Komponenten. Eine DerivedComponent.razor.css-Datei erbt diese Stile.

<ItemGroup>
  <None Update="Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Verwenden Sie den Platzhalteroperator (*), um Bereichsbezeichner für mehrere Dateien freizugeben:

<ItemGroup>
  <None Update="Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Ändern des Basispfads für statische Webressourcen

Die Datei scoped.styles.css wird im Stammverzeichnis der App generiert. Verwenden Sie in der Projektdatei die <StaticWebAssetBasePath>-Eigenschaft, um den Standardpfad zu ändern. Im folgenden Beispiel werden die Datei scoped.styles.css und die restlichen Ressourcen der App unter dem Pfad _content gespeichert:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Deaktivieren der automatischen Bündelung

Wenn Sie das Verhalten von Blazor beim Veröffentlichen und Laden bereichsbezogener Dateien zur Laufzeit ändern möchten, verwenden Sie die DisableScopedCssBundling-Eigenschaft. Die Verwendung dieser Eigenschaft bedeutet, dass die isolierten CSS-Dateien durch andere Tools oder Prozesse aus dem Verzeichnis obj übernommen und zur Laufzeit veröffentlicht und geladen werden:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Deaktivieren der CSS-Isolation

Deaktivieren Sie die CSS-Isolation für ein Projekt, indem Sie die <ScopedCssEnabled>-Eigenschaft in der Projektdatei der App auf false festlegen:

<ScopedCssEnabled>false</ScopedCssEnabled>

Unterstützung für Razor-Klassenbibliothek (RCL)

Isolierte Stile für Komponenten in einem NuGet-Paket oder einer Razor-Klassenbibliothek (RCL) werden automatisch gebündelt:

  • Die App verwendet CSS-Importe, um auf die gebündelten Stile der RCL zu verweisen. Für eine Klassenbibliothek mit dem Namen ClassLib und einer Blazor-App mit einem BlazorSample.styles.css-Stylesheet wird das RCL-Stylesheet oben im Stylesheet der App importiert:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • Die gebündelten Stile der RCL werden nicht als statische Webressource der App veröffentlicht, die die Stile verwendet.

Weitere Informationen zu RCLs finden Sie in den folgenden Artikeln: