ASP.NET Core Blazor の CSS の分離
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
作成者: Dave Brock
この記事では、CSS の分離を使用して Razor コンポーネントに CSS のスコープを設定する方法について説明します。これにより、CSS が簡素化され、他のコンポーネントやライブラリとの競合を回避できます。
CSS スタイルを個々のページ、ビュー、コンポーネントに分離して、次のものを減らすか回避します。
- 維持が困難なグローバル スタイルへの依存関係。
- 入れ子になったコンテンツでのスタイルの競合。
CSS の分離を有効にする
コンポーネント固有のスタイルを定義するには、同じフォルダー内のコンポーネントの .razor
ファイルの名前と一致する .razor.css
ファイルを作成します。 .razor.css
ファイルは、"スコープ付き CSS ファイル" です。
Example.razor
ファイル内の Example
コンポーネントの場合、コンポーネントと共に Example.razor.css
という名前のファイルを作成します。 Example.razor.css
ファイルは、Example
コンポーネント (Example.razor
) と同じフォルダー内に存在する必要があります。 ファイルの "Example
" ベース名では、大文字と小文字が区別されません。
Example.razor
:
@page "/example"
<h1>Scoped CSS Example</h1>
Example.razor.css
:
h1 {
color: brown;
font-family: Tahoma, Geneva, Verdana, sans-serif;
}
Example.razor.css
で定義されるスタイルは、Example
コンポーネントのレンダリングされる出力にのみ適用されます。 CSS の分離は、一致する Razor ファイル内の HTML 要素に適用されます。 アプリ内の他の場所で定義されるどの h1
CSS 宣言も、Example
コンポーネントのスタイルと競合しません。
Note
バンドルが発生したときにスタイルの分離を保証するために、Razor コード ブロックでの CSS のインポートはサポートされていません。
CSS の分離のバンドル
CSS の分離は、ビルド時に発生します。 Blazor により、コンポーネントによってレンダリングされるマークアップと一致するように CSS セレクターが書き換えられます。 これらの書き換えられた CSS スタイルは、バンドルされ、静的アセットとして生成されます。 このスタイルシートは、<head>
タグ内で参照されます (<head>
コンテンツの場所)。 次の <link>
要素は、既定では、Blazor プロジェクト テンプレートから作成されたアプリに追加されます。ここで、プレースホルダー {ASSEMBLY NAME}
はプロジェクトのアセンブリ名です。
<link href="{ASSEMBLY NAME}.styles.css" rel="stylesheet">
次の例は、ホストされている Blazor WebAssemblyClient アプリからのものです。 アプリのアセンブリ名は BlazorSample.Client
です。<link>
は、プロジェクトがホステッド オプションを使用して作成される際に (.NET CLI を使用する場合は Blazor WebAssembly オプション、Visual Studio を使用する場合は -ho|--hosted
[ASP.NET Core ホステッド] チェックボックス)、 プロジェクト テンプレートによって追加されます。
<link href="BlazorSample.Client.styles.css" rel="stylesheet">
バンドルされたファイル内で、各コンポーネントはスコープ識別子に関連付けられます。 スタイル付きコンポーネントごとに、HTML 属性に b-{STRING}
の形式が追加されます。ここで、{STRING}
プレースホルダーは、フレームワークによって生成される 10 文字の文字列です。 この識別子はアプリごとに一意です。 レンダリングされる Counter
コンポーネントでは、Blazor により、スコープ識別子が h1
要素に追加されます。
<h1 b-3xxtam6d07>
{ASSEMBLY NAME}.styles.css
ファイルは、スコープ識別子を使用してスタイル宣言をそのコンポーネントと共にグループ化します。 次の例では、前述の <h1>
要素のスタイルを示します。
/* /Components/Pages/Counter.razor.rz.scp.css */
h1[b-3xxtam6d07] {
color: brown;
}
ビルド時、規則 obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css
でプロジェクト バンドルが作成されます。ここで、プレースホルダーは次のようになります。
{CONFIGURATION}
: アプリのビルド構成 (Debug
、Release
など)。{TARGET FRAMEWORK}
: ターゲット フレームワーク (net6.0
など){ASSEMBLY NAME}
: アプリのアセンブリ名 (例:BlazorSample
)。
子コンポーネントのサポート
既定で、CSS の分離は形式 {COMPONENT NAME}.razor.css
に関連付けられたコンポーネントにのみ適用されます。ここで、プレースホルダー {COMPONENT NAME}
は、通常、コンポーネント名です。 子コンポーネントに変更を適用するには、親コンポーネントの .razor.css
ファイル内の子孫要素に::deep
疑似要素を使用します。 ::deep
疑似要素により、要素の生成されたスコープ識別子の "子孫" である要素が選択されます。
次の例は、Child
という名前の子コンポーネントを持つ Parent
という名前の親コンポーネントを示します。
Parent.razor
:
@page "/parent"
<div>
<h1>Parent component</h1>
<Child />
</div>
Child.razor
:
<h1>Child Component</h1>
::deep
疑似要素を使って Parent.razor.css
内の h1
宣言を更新し、h1
スタイル宣言を親コンポーネントとその子に適用する必要があることを示します。
Parent.razor.css
:
::deep h1 {
color: red;
}
これで、子コンポーネント用の個別のスコープ付き CSS ファイルを作成する必要なく、h1
スタイルは、Parent
と Child
の各コンポーネントに適用されます。
::deep
疑似要素は、子孫要素でのみ機能します。 次のマークアップでは、想定どおりに h1
スタイルがコンポーネントに適用されます。 親コンポーネントのスコープ識別子が div
要素に適用されるため、ブラウザーでは、スタイルを親コンポーネントから継承することが認識されます。
Parent.razor
:
<div>
<h1>Parent</h1>
<Child />
</div>
ただし、div
要素を除外すると、子孫関係が削除されます。 次の例では、スタイルは子コンポーネントに適用されません。
Parent.razor
:
<h1>Parent</h1>
<Child />
::deep
擬似要素は、スコープ属性が規則に適用される場所に影響を与えます。 スコープ付き CSS ファイルで CSS 規則を定義すると、そのスコープは既定で右端の要素に適用されます。 たとえば、div > a
は div > a[b-{STRING}]
に変換されます。この {STRING}
プレースホルダーは、フレームワークによって生成される 10 文字の文字列 (例: b-3xxtam6d07
) です。 代わりに、規則を別のセレクターに適用したい場合は、::deep
擬似要素を使うと実行できます。 たとえば、div ::deep > a
は div[b-{STRING}] > a
に変換されます (例: div[b-3xxtam6d07] > a
)。
任意の HTML 要素に ::deep
擬似要素をアタッチする機能を使うと、レンダリングされた HTML タグの構造を特定できる場合に、他のコンポーネントによってレンダリングされた要素に影響を与えるスコープ付き CSS スタイルを作成できます。 別のコンポーネント内にハイパーリンク タグ (<a>
) をレンダリングするコンポーネントの場合は、そのコンポーネントを div
(または他の任意の要素) でラップし、規則 ::deep > a
を使って、親コンポーネントのレンダリング時にのみそのコンポーネントに適用されるスタイルを作成するようにしてください。
重要
スコープ付き CSS は "HTML 要素" にのみ適用され、Razor コンポーネントやタグ ヘルパーには適用されません (<input asp-for="..." />
のようにタグ ヘルパーが適用された要素など)。
CSS プリプロセッサのサポート
CSS プリプロセッサは、変数、入れ子、モジュール、mixin、継承などの機能を利用することで CSS 開発を改善するのに役立ちます。 CSS の分離は、SASS や LESS などの CSS プリプロセッサをネイティブにサポートしていませんが、ビルド プロセス中に Blazor により CSS セレクターが書き換えられる前にプリプロセッサのコンパイルが行われる限り、CSS プリプロセッサの統合はシームレスです。 たとえば、Visual Studio を使用して、Visual Studio タスク ランナー エクスプローラーで既存のプリプロセッサ コンパイルをビルド前タスクとして構成します。
AspNetCore.SassCompiler
などの多くのサードパーティ製 NuGet パッケージは、CSS の分離が発生する前に、ビルド プロセスの開始時に SASS または SCSS ファイルをコンパイルできます。
CSS の分離の構成
CSS の分離は、すぐに使用できるように設計されていますが、既存のツールやワークフローへの依存関係がある場合など、一部の高度なシナリオ用の構成も用意されています。
スコープ識別子の形式をカスタマイズする
既定では、スコープ識別子には、b-{STRING}
の形式が使用されます。ここで、{STRING}
プレースホルダーは、フレームワークによって生成される 10 文字の文字列です。 スコープ識別子の形式をカスタマイズするには、プロジェクト ファイルを目的のパターンに更新します。
<ItemGroup>
<None Update="Components/Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
前の例では、Example.razor.css
用に生成された CSS により、そのスコープ識別子は b-{STRING}
から custom-scope-identifier
に変更されます。
スコープ識別子を使用して、スコープ付き CSS ファイルでの継承を実現します。 次のプロジェクト ファイルの例では、BaseComponent.razor.css
ファイルに、コンポーネント間の共通スタイルが含まれています。 DerivedComponent.razor.css
ファイルでは、これらのスタイルが継承されます。
<ItemGroup>
<None Update="Components/Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
<None Update="Components/Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
ワイルドカード (*
) 演算子を使用して、複数のファイル間でスコープ識別子を共有します。
<ItemGroup>
<None Update="Components/Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
既定では、スコープ識別子には、b-{STRING}
の形式が使用されます。ここで、{STRING}
プレースホルダーは、フレームワークによって生成される 10 文字の文字列です。 スコープ識別子の形式をカスタマイズするには、プロジェクト ファイルを目的のパターンに更新します。
<ItemGroup>
<None Update="Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
前の例では、Example.razor.css
用に生成された CSS により、そのスコープ識別子は b-{STRING}
から custom-scope-identifier
に変更されます。
スコープ識別子を使用して、スコープ付き CSS ファイルでの継承を実現します。 次のプロジェクト ファイルの例では、BaseComponent.razor.css
ファイルに、コンポーネント間の共通スタイルが含まれています。 DerivedComponent.razor.css
ファイルでは、これらのスタイルが継承されます。
<ItemGroup>
<None Update="Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
<None Update="Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
ワイルドカード (*
) 演算子を使用して、複数のファイル間でスコープ識別子を共有します。
<ItemGroup>
<None Update="Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>
静的な Web アセットのベース パスを変更する
scoped.styles.css
ファイルは、アプリのルートで生成されます。 プロジェクト ファイルでは、<StaticWebAssetBasePath>
プロパティを使用して既定のパスを変更します。 次の例では、scoped.styles.css
ファイルとアプリの残りのアセットを _content
パスに配置します。
<PropertyGroup>
<StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>
自動バンドルを無効にする
Blazor でスコープ付きファイルを公開し、それを実行時に読み込む方法をオプトアウトするには、DisableScopedCssBundling
プロパティを使用します。 このプロパティを使用する場合、obj
ディレクトリからの CSS ファイルの分離と、それらの公開および実行時の読み込みを他のツールまたはプロセスが担当することを意味します。
<PropertyGroup>
<DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>
CSS の分離を無効にする
アプリのプロジェクト ファイルで <ScopedCssEnabled>
プロパティを false
に設定することでプロジェクトの CSS 分離を無効にします。
<ScopedCssEnabled>false</ScopedCssEnabled>
Razor クラス ライブラリ (RCL) のサポート
NuGet パッケージまたは Razor クラス ライブラリ (RCL) のコンポーネントの分離スタイルは自動的にバンドルされます。
アプリでは CSS インポートを使用し、RCL のバンドルされたスタイルを参照します。
ClassLib
という名前のクラス ライブラリと、BlazorSample.styles.css
スタイルシートのある Blazor アプリについては、アプリのスタイルシートの一番上に RCL のスタイルシートがインポートされます。@import '_content/ClassLib/ClassLib.bundle.scp.css';
RCL のバンドルされたスタイルは、スタイルを使用するアプリの静的な Web アセットとして公開されません。
RCL の詳細については、次の記事を参照してください。
その他のリソース
ASP.NET Core
フィードバック
フィードバックの送信と表示