Isolamento CSS di ASP.NET Core Blazor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Scritto da Dave Brock

Questo articolo illustra in che modo l'isolamento CSS limita il CSS ai componenti Razor, che può semplificare il CSS ed evitare conflitti con altri componenti o librerie.

Isolare gli stili CSS in singole pagine, visualizzazioni e componenti per ridurre o evitare:

  • Dipendenze da stili globali che possono risultare difficili da gestire.
  • Conflitti di stile nel contenuto annidato.

Abilita isolamento CSS

Per definire stili specifici del componente, creare un .razor.css file corrispondente al nome del .razor file per il componente nella stessa cartella. Il .razor.css file è un file CSS con ambito.

Per un componente Example in un file Example.razor, creare un file nella stessa cartella del componente denominato Example.razor.css. Il Example.razor.css file deve trovarsi nella stessa cartella del Example componente (Example.razor). Il nome di base "Example" del file non fa distinzione tra maiuscole e minuscole.

Example.razor:

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css:

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

Gli stili definiti in Example.razor.css vengono applicati solo all'output sottoposto a rendering del Example componente. L'isolamento CSS viene applicato agli elementi HTML nel file corrispondente Razor . Le h1 dichiarazioni CSS definite altrove nell'app non sono in conflitto con gli stili del componente Example.

Nota

Per garantire l'isolamento dello stile quando si verifica la creazione di bundle, l'importazione di CSS nei Razor blocchi di codice non è supportata.

Bundling dell'isolamento CSS

L'isolamento CSS si verifica in fase di compilazione. Blazor riscrive i selettori CSS in modo che corrispondano al markup sottoposto a rendering dal componente. Gli stili CSS riscritti vengono inclusi nel bundle e prodotti come asset statico. Viene fatto riferimento al foglio di stile all'interno del tag <head> (posizione del contenuto di <head>). L'elemento seguente <link> viene aggiunto a un'app creata dai modelli di Blazor progetto:

Blazor Web App:

<link href="@Assets["{PACKAGE ID/ASSEMBLY NAME}.styles.css"]" rel="stylesheet">

App Blazor WebAssembly autonome:

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

Il {PACKAGE ID/ASSEMBLY NAME} segnaposto è l'ID pacchetto del progetto (<PackageId> nel file di progetto) per una libreria o un nome di assembly per un'app.

L'esempio seguente proviene da un'app hosted Blazor WebAssemblyClient. Il nome dell'assembly dell'app è BlazorSample.Client e <link> viene aggiunto dal modello di progetto Blazor WebAssembly quando il progetto viene creato con l'opzione Hosted (-ho|--hosted opzione che usa l'interfaccia della riga di comando di .NET o la casella di controllo ASP.NET Core Hosted con Visual Studio):

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

All'interno del file in bundle, ogni componente è associato a un identificatore di ambito. Per ogni componente in stile, un attributo HTML viene aggiunto con il formato b-{STRING}, dove il {STRING} segnaposto è una stringa di dieci caratteri generata dal framework. L'identificatore è univoco per ogni app. Nel componente Counter renderizzato, Blazor aggiunge un identificatore di ambito all'elemento h1:

<h1 b-3xxtam6d07>

Il {PACKAGE ID/ASSEMBLY NAME}.styles.css file usa l'identificatore di ambito per raggruppare una dichiarazione di stile con il relativo componente. Nell'esempio seguente viene fornito lo stile per l'elemento precedente <h1> :

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

In fase di compilazione viene creato un bundle di progetto con la convenzione obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{PACKAGE ID/ASSEMBLY NAME}.bundle.scp.css, dove i segnaposto sono:

  • {CONFIGURATION}: la configurazione di compilazione dell'app , ad esempio Debug, Release.
  • {TARGET FRAMEWORK}: Il framework di destinazione (ad esempio, net6.0).
  • {PACKAGE ID/ASSEMBLY NAME}: ID pacchetto del progetto (<PackageId> nel file di progetto) per una libreria o un nome di assembly per un'app (ad esempio, BlazorSample).

Supporto per i componenti figlio

L'isolamento CSS si applica solo al componente associato al formato {COMPONENT NAME}.razor.css, dove il segnaposto {COMPONENT NAME} è solitamente il nome del componente. Per applicare le modifiche a un componente figlio, utilizzare lo ::deeppseudoelemento su tutti gli elementi discendenti nel file del .razor.css componente padre. Lo ::deep pseudoelemento seleziona gli elementi discendenti dell’ambito generato di un elemento.

Nell'esempio seguente viene illustrato un componente padre denominato Parent con un componente figlio denominato Child.

Parent.razor:

@page "/parent"

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

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

Aggiornare la dichiarazione h1 in Parent.razor.css con lo pseudoelemento ::deep per indicare che la dichiarazione di stile h1 deve essere applicata al componente padre e ai relativi elementi figlio.

Parent.razor.css:

::deep h1 { 
    color: red;
}

Lo h1 stile ora si applica ai componenti Parent e Child senza la necessità di creare un file CSS con ambito separato per il componente figlio.

Lo ::deep pseudoelemento funziona solo con gli elementi discendenti. Il markup seguente applica gli h1 stili ai componenti come previsto. L'identificatore di ambito del componente padre viene applicato all'elemento div, quindi il browser sa che deve ereditare gli stili dal componente padre.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

Tuttavia, l'esclusione dell'elemento div rimuove la relazione di discendenza. Nell'esempio seguente lo stile non viene applicato al componente figlio.

Parent.razor:

<h1>Parent</h1>

<Child />

Lo ::deep pseudoelemento influisce sulla posizione in cui l'attributo scope viene applicato alla regola. Quando si definisce una regola CSS in un file CSS con ambito, l'ambito viene applicato all'elemento più a destra. Ad esempio: div > a viene trasformato in div > a[b-{STRING}], dove il {STRING} segnaposto è una stringa di dieci caratteri generata dal framework , ad esempio b-3xxtam6d07. Se invece si desidera che la regola venga applicata a un selettore diverso, lo ::deep pseudoelemento consente di farlo. Ad esempio, div ::deep > a viene trasformato in div[b-{STRING}] > a (ad esempio, div[b-3xxtam6d07] > a).

La possibilità di associare lo ::deep pseudoelemento a qualsiasi elemento HTML consente di creare stili CSS con ambito che influiscono sugli elementi sottoposti a rendering da altri componenti quando è possibile determinare la struttura dei tag HTML sottoposti a rendering. Per un componente che esegue il rendering di un tag di collegamento ipertestuale (<a>) all'interno di un altro componente, verificare che il componente sia racchiuso in un elemento div (o qualsiasi altro elemento) e usare la regola ::deep > a per creare uno stile applicato solo a tale componente quando viene eseguito il rendering del componente padre.

Importante

CSS con ambito si applica solo agli elementi HTML e non ai componenti o agli Razor helper tag, inclusi gli elementi con un helper tag applicato, ad esempio <input asp-for="..." />.

Supporto dei preprocessori CSS

I preprocessori CSS sono utili per migliorare lo sviluppo di CSS tramite l'utilizzo di funzionalità come variabili, annidamenti, moduli, mixin ed ereditarietà. Anche se l'isolamento CSS non supporta in modo nativo preprocessori CSS, ad esempio Sass o Less, l'integrazione dei preprocessori CSS è facile, purché la compilazione del preprocessore venga eseguita prima che Blazor riscriva i selettori CSS durante il processo di compilazione. Usando Visual Studio, ad esempio, configura la compilazione del preprocessore esistente come attività Prima di compilare in Task Runner Explorer.

Molti pacchetti NuGet di terze parti, ad esempio AspNetCore.SassCompiler, possono compilare file SASS/SCSS all'inizio del processo di compilazione prima che si verifichi l'isolamento CSS.

Configurazione dell'isolamento CSS

L'isolamento CSS è progettato per funzionare correttamente, ma fornisce la configurazione per alcuni scenari avanzati, ad esempio quando sono presenti dipendenze da strumenti o flussi di lavoro esistenti.

Personalizzare il formato dell'identificatore di ambito

Gli identificatori di ambito usano il formato b-{STRING}, dove il {STRING} segnaposto è una stringa di dieci caratteri generata dal framework. Per personalizzare il formato dell'identificatore di ambito, aggiornare il file di progetto a un modello desiderato:

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

Nell'esempio precedente il file CSS generato per Example.razor.css cambia il relativo identificatore di ambito da b-{STRING} a custom-scope-identifier.

Usare gli identificatori di ambito per ottenere l'ereditarietà con i file CSS con ambito. Nell'esempio di file di progetto seguente un BaseComponent.razor.css file contiene stili comuni tra i componenti. Un file DerivedComponent.razor.css eredita questi stili.

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

Usare l'operatore carattere jolly (*) per condividere gli identificatori di ambito tra più file:

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

Gli identificatori di ambito usano il formato b-{STRING}, dove il {STRING} segnaposto è una stringa di dieci caratteri generata dal framework. Per personalizzare il formato dell'identificatore di ambito, aggiornare il file di progetto a un modello desiderato:

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

Nell'esempio precedente il file CSS generato per Example.razor.css cambia il relativo identificatore di ambito da b-{STRING} a custom-scope-identifier.

Usare gli identificatori di ambito per ottenere l'ereditarietà con i file CSS con ambito. Nell'esempio di file di progetto seguente un BaseComponent.razor.css file contiene stili comuni tra i componenti. Il file DerivedComponent.razor.css eredita questi stili.

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

Usare l'operatore carattere jolly (*) per condividere gli identificatori di ambito tra più file:

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

Cambiare il percorso di base per gli asset Web statici

Il scoped.styles.css file viene generato nella radice dell'app. Nel file di progetto usare la <StaticWebAssetBasePath> proprietà per modificare il percorso predefinito. L'esempio seguente inserisce il file scoped.styles.css e il resto degli asset dell'app nel percorso _content:

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

Disabilita il raggruppamento automatico

Per disattivare la modalità con cui Blazor pubblica e carica i file con ambito definito in fase di esecuzione, usare la proprietà DisableScopedCssBundling. Quando si usa questa proprietà, significa che altri strumenti o processi sono responsabili di prelevare i file CSS isolati dalla directory obj e della loro pubblicazione e del caricamento in fase di esecuzione:

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

Disabilita l'isolamento CSS

Disabilitare l'isolamento CSS per un progetto impostando la <ScopedCssEnabled> proprietà su false nel file di progetto dell'app:

<ScopedCssEnabled>false</ScopedCssEnabled>

Supporto per la libreria di classi Razor Razor (RCL)

Gli stili isolati per i componenti in un pacchetto NuGet o Razoruna libreria di classi (RCL) vengono raggruppati automaticamente:

  • L'app usa le importazioni CSS per fare riferimento agli stili in bundle di RCL. Per una libreria di classi denominata ClassLib e un'app Blazor con un BlazorSample.styles.css foglio di stile, il foglio di stile rcl viene importato nella parte superiore del foglio di stile dell'app:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • Gli stili in bundle di RCL non vengono pubblicati come asset Web statici dell'app che utilizza gli stili.

Per altre informazioni sulle librerie di classi Razor (RCL), vedere gli articoli seguenti: