isolasi CSS ASP.NET Core Blazor

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

Peringatan

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

Oleh Dave Brock

Artikel ini menjelaskan bagaimana isolasi CSS membatasi CSS pada komponen Razor, yang dapat menyederhanakan CSS dan menghindari tabrakan dengan komponen atau pustaka lain.

Pisahkan gaya CSS ke halaman, tampilan, dan komponen individual untuk mengurangi atau menghindari:

  • Dependensi pada gaya global yang sulit dipertahankan.
  • Konflik gaya dalam konten yang disarangkan.

Mengaktifkan isolasi CSS

Untuk menentukan gaya khusus komponen, buat file .razor.css yang cocok dengan nama file .razor untuk komponen di folder yang sama. File .razor.css adalah file CSS dengan cakupan terbatas.

Example Untuk komponen dalam file Example.razor, buat file di folder yang sama dengan komponen bernama Example.razor.css. File Example.razor.css harus berada di folder yang sama dengan Example komponen (Example.razor). Nama dasar file "Example" tidak peka huruf besar/kecil.

Example.razor:

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css:

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

Gaya yang ditentukan di Example.razor.css hanya diterapkan ke output hasil render dari komponen Example. Isolasi CSS diterapkan ke elemen HTML dalam file Razor yang sesuai. Deklarasi CSS apa pun yang ditentukan h1 di tempat lain dalam aplikasi tidak bertentangan dengan gaya komponen Example.

Catatan

Untuk menjamin isolasi gaya saat bundling terjadi, mengimpor CSS dalam Razor blok kode tidak didukung.

Pembundelan isolasi CSS

Isolasi CSS terjadi pada waktu pembuatan. Blazor menulis ulang pemilih CSS agar sesuai dengan markup yang dirender oleh komponen. Gaya CSS yang ditulis ulang dibundel dan diproduksi sebagai aset statis. Lembar gaya direferensikan di dalam tag <head> (lokasi konten <head>). Elemen berikut <link> ditambahkan ke aplikasi yang dibuat dari Blazor templat proyek:

Blazor Web AppS:

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

Aplikasi Blazor WebAssembly mandiri:

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

Placeholder {PACKAGE ID/ASSEMBLY NAME} adalah ID paket proyek (<PackageId> dalam file proyek) untuk pustaka atau nama rakitan aplikasi.

Contoh berikut berasal dari aplikasi yang di-host Blazor WebAssemblyClient. Nama rakitan aplikasi adalah BlazorSample.Client, dan <link> ditambahkan oleh templat proyek Blazor WebAssembly saat proyek dibuat dengan opsi Dihosting (-ho|--hosted opsi menggunakan .NET CLI atau kotak centang ASP.NET Core Hosted menggunakan Visual Studio):

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

Dalam file yang dibundel, setiap komponen dikaitkan dengan pengidentifikasi cakupan. Untuk setiap komponen yang ditata, atribut HTML ditambahkan dengan format b-{STRING}, di mana placeholder {STRING} adalah string sepuluh karakter yang dihasilkan oleh kerangka kerja. Pengidentifikasi ini unik untuk setiap aplikasi. Dalam komponen yang dirender Counter , Blazor menambahkan pengidentifikasi cakupan ke h1 elemen :

<h1 b-3xxtam6d07>

File {PACKAGE ID/ASSEMBLY NAME}.styles.css menggunakan pengidentifikasi cakupan untuk mengelompokkan deklarasi gaya dengan komponennya. Contoh berikut menunjukkan gaya untuk elemen sebelumnya <h1>:

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

Pada waktu build, bundel proyek dibuat dengan konvensi obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{PACKAGE ID/ASSEMBLY NAME}.bundle.scp.css, di mana placeholder adalah:

  • {CONFIGURATION}: Konfigurasi build aplikasi (misalnya, Debug, Release).
  • {TARGET FRAMEWORK}: Kerangka kerja target (misalnya, net6.0).
  • {PACKAGE ID/ASSEMBLY NAME}: ID paket proyek (<PackageId> dalam file proyek) untuk pustaka atau nama rakitan untuk aplikasi (misalnya, BlazorSample).

Dukungan komponen turunan

Isolasi CSS hanya berlaku untuk komponen yang Anda kaitkan dengan format {COMPONENT NAME}.razor.css, di mana placeholder {COMPONENT NAME} biasanya merupakan nama komponen. Untuk menerapkan perubahan pada komponen anak, gunakan ::deeppseudo-element pada elemen turunan apa pun dalam .razor.css file komponen induk. Elemen semu ::deep memilih elemen yang merupakan keturunan dari pengidentifikasi cakupan yang dihasilkan elemen.

Contoh berikut menunjukkan komponen induk yang dipanggil Parent dengan komponen turunan yang disebut Child.

Parent.razor:

@page "/parent"

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

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

Perbarui deklarasi h1 di Parent.razor.css dengan elemen pseudo ::deep untuk menandakan deklarasi gaya h1 harus berlaku untuk komponen induk dan turunannya.

Parent.razor.css:

::deep h1 { 
    color: red;
}

Gaya h1 sekarang berlaku untuk komponen Parent dan Child tanpa perlu membuat file CSS terlingkup terpisah untuk komponen anak.

Pseudo-element ::deep hanya berfungsi dengan elemen turunan. Markup berikut menerapkan gaya h1 ke komponen seperti yang diharapkan. Pengidentifikasi cakupan komponen induk diterapkan ke div elemen , sehingga browser tahu untuk mewarisi gaya dari komponen induk.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

Namun, mengecualikan elemen div menghapus hubungan turunan. Dalam contoh berikut, gaya tidak diterapkan ke komponen anak.

Parent.razor:

<h1>Parent</h1>

<Child />

Elemen ::deep pseudo memengaruhi di mana atribut cakupan diterapkan ke aturan. Saat Anda menentukan aturan CSS dalam file CSS terlingkup, cakupan diterapkan ke elemen paling kanan. Misalnya: div > a diubah menjadi div > a[b-{STRING}], di mana {STRING} placeholder adalah string sepuluh karakter yang dihasilkan oleh kerangka kerja (misalnya, b-3xxtam6d07). Jika Anda sebaliknya ingin aturan diterapkan ke pemilih yang berbeda, ::deep elemen pseudo memungkinkan aturan tersebut diterapkan demikian. Misalnya, div ::deep > a diubah menjadi div[b-{STRING}] > a (misalnya, div[b-3xxtam6d07] > a).

Kemampuan untuk melampirkan ::deep elemen pseudo ke elemen HTML apa pun memungkinkan Anda membuat gaya CSS tercakup yang memengaruhi elemen yang dirender oleh komponen lain ketika Anda dapat menentukan struktur tag HTML yang dirender. Untuk komponen yang merender tag hyperlink (<a>) di dalam komponen lain, pastikan komponen dibungkus dalam div (atau elemen lain) dan gunakan aturan ::deep > a untuk membuat gaya yang hanya diterapkan ke komponen tersebut saat komponen induk merender.

Penting

Scoped CSS hanya berlaku untuk elemen HTML dan bukan untuk komponen Razor atau Tag Helper, termasuk elemen dengan Tag Helper yang diterapkan, seperti <input asp-for="..." />.

Dukungan praprosesor CSS

Praprosesor CSS berguna untuk meningkatkan pengembangan CSS dengan memanfaatkan fitur seperti variabel, bersarang, modul, mixin, dan pewarisan. Meskipun isolasi CSS tidak secara asli mendukung praprosesor CSS seperti Sass atau Less, integrasi praprosesor CSS berjalan mulus selama kompilasi praprosesor terjadi sebelum Blazor menulis ulang pemilih CSS selama proses build. Menggunakan Visual Studio sebagai contoh, konfigurasikan kompilasi praprosesor yang ada sebagai tugas Before Build di Visual Studio Task Runner Explorer.

Banyak paket NuGet pihak ketiga, seperti AspNetCore.SassCompiler, dapat mengkompilasi file SASS/SCSS di awal proses build sebelum isolasi CSS terjadi.

Konfigurasi isolasi CSS

Isolasi CSS dirancang untuk langsung dapat digunakan tetapi menyediakan konfigurasi untuk beberapa skenario tingkat lanjut, seperti ketika ada dependensi pada alat atau alur kerja yang ada.

Sesuaikan format pengenal cakupan

Pengidentifikasi cakupan menggunakan format b-{STRING}, di mana placeholder {STRING} adalah string sepuluh karakter yang dihasilkan oleh kerangka kerja. Untuk mengkustomisasi format pengidentifikasi cakupan, perbarui file proyek menjadi pola yang diinginkan:

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

Pada contoh sebelumnya, CSS yang dihasilkan untuk Example.razor.css mengubah pengidentifikasi cakupannya dari b-{STRING} menjadi custom-scope-identifier.

Gunakan identifier cakupan untuk mencapai pewarisan dengan file CSS dengan cakupan tertentu. Dalam contoh file proyek berikut, BaseComponent.razor.css file berisi gaya umum di seluruh komponen. File DerivedComponent.razor.css ini mewarisi gaya ini.

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

Gunakan operator wildcard (*) untuk berbagi pengidentifikasi cakupan di beberapa file:

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

Pengidentifikasi cakupan menggunakan format b-{STRING}, di mana placeholder {STRING} adalah string sepuluh karakter yang dihasilkan oleh kerangka kerja. Untuk mengkustomisasi format pengidentifikasi cakupan, perbarui file proyek menjadi pola yang diinginkan:

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

Pada contoh sebelumnya, CSS yang dihasilkan untuk Example.razor.css mengubah pengidentifikasi cakupannya dari b-{STRING} menjadi custom-scope-identifier.

Gunakan identifier cakupan untuk mencapai pewarisan dengan file CSS dengan cakupan tertentu. Dalam contoh file proyek berikut, BaseComponent.razor.css file berisi gaya umum di seluruh komponen. File DerivedComponent.razor.css ini mewarisi gaya ini.

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

Gunakan operator wildcard (*) untuk berbagi pengidentifikasi cakupan di beberapa file:

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

Mengubah jalur dasar untuk aset web statis

File scoped.styles.css dihasilkan di akar aplikasi. Dalam file proyek, gunakan properti <StaticWebAssetBasePath> untuk mengubah jalur default. Contoh berikut menempatkan file scoped.styles.css dan aset aplikasi lainnya di jalur _content.

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

Nonaktifkan bundling otomatis

Untuk menonaktifkan cara Blazor menerbitkan dan memuat file terlingkup saat runtime, gunakan properti DisableScopedCssBundling. Saat menggunakan properti ini, itu berarti alat atau proses lain bertanggung jawab untuk mengambil file CSS yang terisolasi dari obj direktori dan menerbitkan dan memuatnya pada runtime:

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

Nonaktifkan isolasi CSS

Nonaktifkan isolasi CSS untuk proyek dengan mengatur properti <ScopedCssEnabled> menjadi false dalam file proyek aplikasi:

<ScopedCssEnabled>false</ScopedCssEnabled>

Razor dukungan pustaka kelas (RCL)

Gaya terisolasi untuk komponen dalam paket NuGet atau Razor pustaka kelas Razor (RCL) dibundel secara otomatis:

  • Aplikasi ini menggunakan impor CSS untuk mereferensikan gaya bundel RCL. Untuk pustaka kelas bernama ClassLib dan Blazor aplikasi dengan BlazorSample.styles.css lembar gaya, lembar gaya RCL diimpor di bagian atas lembar gaya aplikasi:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • Gaya yang dibundel RCL tidak didistribusikan sebagai aset web statis aplikasi yang menggunakan gaya.

Untuk informasi lebih lanjut tentang RCL, lihat artikel berikut: