Blazor における CSS 分離の問題

Blazor における CSS 分離の問題

1. 環境

VS 2019 16.9.0 プレビュー 1.0

.NET SDK 5.0.100

2. はじめに

CSS が有効になると、グローバルに適用されるため、競合が発生する可能性があります。この問題を解決するために、CSS 分離が誕生しました。 Blazor は 2018 年に誕生しました。つまり、2 年以上前のことです。ただし、CSS 分離は .NET 5 までサポートされていませんでした。

3. Razorコンポーネント間の分離

Razor コンポーネント間の CSS 分離は、CSS 分離を使用する最もシンプルで便利な方法です。 Razor コンポーネント間の CSS 分離を実現するのは非常に簡単です。コンポーネントが配置されているディレクトリに同じ名前の ".razor.css" ファイルを作成するだけです。フォルダー A に "Component.razor" という名前のコンポーネントがある場合、フォルダー A に "Component.razor.css" を作成するだけで、他のコンポーネントに影響を与えずに "Component.razor" コンポーネントに別のスタイルを設定できます。

デフォルトのテンプレートを例に、次の内容の新しい「Index.razor.css」を作成します。

h1 {
    フォントサイズ: 48px;
    フォントの太さ: 太字;
}

次の内容で新しい「Counter.razor.css」を作成します。

h1 {
    フォントサイズ: 16px;
    フォントの太さ: 400;
}

効果は以下のとおりです。

上記のコンポーネント CSS ファイルは、「プロジェクト名.styles.css」ファイルとして生成され、.NET 5 ではデフォルトで「index.html」に追加されます。上記の 2 つの CSS ファイルは、次の結果にコンパイルされます。

/* /Pages/Counter.razor.rz.scp.css */
h1[b-g5zg69lne1] {
    フォントサイズ: 16px;
    フォントの太さ: 400;
}
/* /Pages/Index.razor.rz.scp.css */
h1[b-f3rb2cn7la] {
    フォントサイズ: 48px;
    フォントの太さ: 太字;
}

ブラウザで DOM 要素を表示すると、結果は次のようになります。

<h1 b-f3rb2cn7la>こんにちは、世界!</h1>

<h1 b-g5zg69lne1>カウンター</h1>

つまり、これら 2 つのコンポーネントの DOM に、「b-」で始まり、ランダムな 10 文字が続く属性が追加されます。これは Angular に似ているようです (私は使用したことはありませんが、ブラウザーで同様のものを見たことがあります)。 Blazor での CSS の分離は、ランダムなプロパティ名によって実現されるようです。では、id と class を使用して style.css を生成するとどうなるでしょうか?これもランダムな属性名によって実現されます。たとえば、次のコンポーネント CSS ファイル:

#zxyao-a {
    フォントサイズ: 48px;
    フォントの太さ: 太字;
}

#zxyao-b {
    フォントサイズ: 24px;
    フォントの太さ: 太字;
    背景色: #ff0000;
    パディング: 16px;
}

.zxyao-cls {
    フォントサイズ: 24px;
    フォントの太さ: 太字;
    背景色: #000;
    色: #fff;
    パディング: 16px;
}

次のような結果にコンパイルされます。

/* /Pages/Index.razor.rz.scp.css */
#zxyao-a[b-f3rb2cn7la] {
    フォントサイズ: 48px;
    フォントの太さ: 太字;
}

#zxyao-b[b-f3rb2cn7la] {
    フォントサイズ: 24px;
    フォントの太さ: 太字;
    背景色: #ff0000;
    パディング: 16px;
}

.zxyao-cls[b-f3rb2cn7la] {
    フォントサイズ: 24px;
    フォントの太さ: 太字;
    背景色: #000;
    色: #fff;
    パディング: 16px;
}

結果は次のとおりです。

つまり、コンポーネント CSS ファイルのサマリーがどのように記述されていても、CSS セレクタ [ランダム属性] の形式に変換されます。

4. CSS 分離サブコンポーネントのサポート

デフォルトでは、コンポーネント CSS は現在のコンポーネントにのみ適用されます。たとえば、次の 2 つのコンポーネントがあります。

/* Index.razor */
<div class="my-text">
    新しいアプリへようこそ。
    <CssIsolation.Components.Child />
</div>

/* コンポーネント/Child.razor */
<h1>子供</h1>
<div class="my-text">
    これは子コンポーネントです</div>

「Index.razor.css」のスタイルが次のようになっている場合、

.my-text {
    境界線:2px実線 #000;
    パディング: 16px;
}

そうすると、「Index.razor」に対してのみ機能し、境界線は最も外側の Index コンポーネントに表示されます。

このコンポーネントとそのサブコンポーネント「.my-text」要素で動作させたい場合は、「::deep」を使用してマークすることができます。

::deep .my-text {
    境界線:2px実線 #000;
    パディング: 16px;
} 

このコンポーネントの「.my-text」の境界線が消えていることに気づきましたか?前述したように、ここでは ::deep がランダムな属性に置き換えられます。つまり、コンパイル結果は次のようになります。

/* /Pages/Index.razor.rz.scp.css */
[b-f3rb2cn7la] .my-text {
    境界線:2px実線 #000;
    パディング: 16px;
}

このうち、b-f3rb2cn7la は、図に示すように、このコンポーネントのルート要素を参照します。

このグループ内に一意の親要素タグがない場合、このグループ内の各ネイティブ HTML タグは同じランダム属性を持ちます。たとえば、以下のコンポーネントでは、「div」と「h1」の両方が同じランダム属性を持ち、「::deep」フラグがこの属性に置き換えられます。 「子」コンポーネント内の要素にはランダムな属性はありません。

<div class="my-text">
    新しいアプリへようこそ。
</div>
<h1>
    新しいアプリへようこそ。
</h1>
<CssIsolation.Components.Child />

一部のコンポーネント ライブラリでは、Ant Design Blazor などの「テンプレート」などのコンポーネントが提供されています。次のように、コンポーネントを使用してすべての要素をラップするとします。

<AntDesign.テンプレート>
    <div class="my-text">
        新しいアプリへようこそ。
        <CssIsolation.Components.Child />
    </div>
</AntDesign.テンプレート>

Blazor は、このグループ内の最初のネイティブ HTML 要素が見つかるまで外側のコンポーネントを無視し、その後、このレイヤー内のすべてのネイティブ HTML 要素にランダムな属性を追加します。

したがって、このコンポーネントのルート要素に、サブコンポーネントでスタイルを設定する必要がある要素と同じ CSS セレクターがある場合、このコンポーネントとサブコンポーネントの両方にスタイルを適用するように分離するには、このグループとサブコンポーネントの CSS スタイルを同時に記述する方法と、すべてのコンポーネントと要素を 1 つの要素でラップする、つまりルート要素を変更する方法の 2 つの方法があります。

5. CSSプリプロセッサのサポート

多くの場合、スタイル ファイルの作成には SCSS または LESS を使用します。Blazor はこれらのプリプロセッサをネイティブにサポートしていません。プロジェクトが生成される前にタスク ランナー リソース マネージャーを使用して SCSS または LESS をコンパイルするか、Microsoft が言及している Delegate.SassBuilder などのサードパーティ ライブラリを使用してサポートすることができます。 Delegate.SassBuilder を試してみました。使い方が間違っていたせいか、CSS ファイルの生成がプロジェクトの生成より遅く、初めてプログラムを生成したときに CSS ファイルをコンパイルできませんでした。次に、別の方法を紹介します。「タスク ランナー エクスプローラー」を使用する方法です。

ここでは、単に「node-sass」を使用し、Gulp や Webpack などの高度なツールを使用せずに、コマンドラインから直接コンパイルしました。解決手順は次のとおりです (node-sass のインストールについてはここでは説明しません)。

拡張機能「Command Task Runner」をダウンロードしてインストールします

SCSSファイルのコンパイルコマンドラインプログラム「scss.bat」を記述します。

プロジェクトのルート ディレクトリに新しい scss.bat ファイルを作成します。

そして、以下のコマンドを記述します。

node-sass -r ./ -o ./ --source-map true --source-map-contents sass --output-style 圧縮

このコマンドは、SCSS ファイルをコンパイルし、圧縮された CSS ファイルと対応するソース マップ ファイルを生成します。

タスクランナーにbatファイルを追加する

scss.bat ファイルを右クリックし、「タスク ランナーに追加」オプションを選択します。

バインド実行タスク

[表示] | [その他のウィンドウ] | [タスク ランナー エクスプローラー] を開き、scss コマンドを見つけて右クリックし、[バインド] | [生成前] を選択します。バインド後、右側の [バインド] ウィンドウの [生成前] の下にコマンドが表示されます。

タスク ランナーを有効にすると、ソリューション ディレクトリに「commands.json」ファイルが生成されます。ファイルの内容は次のとおりです。「-vs-binding」オプションは、タスク バインディングのランタイムの場所を示します。

{
  「コマンド」: {
    "scss": {
      "ファイル名": "cmd.exe",
      "作業ディレクトリ": ".",
      "引数": "/c scss.bat"
    }
  },
  "-vs-binding": { "BeforeBuild": [ "scss" ] }
}

次に、プログラムを直接実行して効果を確認します。

もちろん、SCSS では「::deep」タグも使用でき、これも正しく表示できます。次に例を示します。

/* ページ/Index.razor.scss */
.my-text {
    境界線: 2px実線 #000;
    パディング: 16px;

    ::深い {
           .my-text {
            境界線: 2px 実線 #ff0000;
            背景色: #000;
            色: #fff;
        }
    }
}

/* コンポーネント/Child.razor.scss */
h1 {
    背景色: #efefef;
    フォントの太さ: 700;
}

対応する Razor コンポーネントは次のとおりです。

/* ページ/インデックス.razor */
@ページ "/"

<div class="my-text">
    新しいアプリへようこそ。
    <CssIsolation.Components.Child />
</div>

/* コンポーネント/Child.razor */
<h1>子供</h1>
<div class="my-text">
    これは子コンポーネントです</div>

操作効果は以下のとおりです。

ただし、SCSS で「::deep」タグを使用すると、少し混乱する可能性があると個人的には感じています。「::deep」タグを使用しないか、以下に示すように「::deep」タグを最外層に配置することをお勧めします。

// いくつかの SCSS スタイル コード...


::深い {
	// サブコンポーネント用のいくつかの SCSS スタイル コード ...
}


// いくつかの SCSS スタイル コード...

6. ランダム属性識別を変更する

前述のように、Blazor によって生成されるランダム属性名のデフォルト形式は、「b-」に続く 10 個のランダムな文字で始まります。Microsoft の公式ドキュメントには、これを変更できることが示されています。これは、独自のアプリケーションにとってより使いやすいものです。たとえば、Xiaomi は「mi」で始まるランダム属性フォームを定義でき、Taobao は「tb」で始まるランダム属性フォームを定義できます。しかし、この機能には問題があるようです。誰かが Github で問題を提起しました - カスタム CSS スコープ識別子が機能しない。Blazor がますます完璧になることを願っています。

Blazor での CSS 分離に関するこの記事はこれで終わりです。Blazor での CSS 分離の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  HTML で水平ナビゲーション構造を設定する方法

>>:  MySQL 8.0はJSONを扱えるようになりました

推薦する

Linux サーバーは最大いくつのポートを開くことができますか?

目次ポート関連の概念:ポートとサービスの関係1: nmapツールが開いているポートを検出する2: n...

Vue-Routerのインストールと使用方法の詳細な説明

目次インストールルーティングの基本構成Vue にルーターをインストールするルーターの設定Router...

Centos 7にmysql5.7.24バイナリバージョンをインストールする方法と解決方法

MySQLバイナリのインストール方法mysqlをダウンロード参考: 1. パッケージを解凍する ta...

macOS での MySQL 8.0.16 のインストールと設定のグラフィック チュートリアル

この記事では、macOSでのMySQL 8.0.16のインストールと設定のチュートリアルを参考までに...

JavaScriptはXiaomi Mall公式サイトの完全なページ実装プロセスを模倣します

目次1. ホームページ制作1. ダウンロードアプリの制作2. ナビゲーションバーの制作3. カルーセ...

暗号化における https の Apache 展開の概要

目次目的実験環境実験原理実験手順1. 独立したCAを生成する2. サーバーの秘密鍵と署名要求ファイル...

Vueは買い物数量を変更できるショッピングカートを実装します

この記事では、Vueを使用してショッピングカートの数量を変更する方法を紹介します。具体的な内容は次の...

選択/フォーカス時にすべてのオプションをリストする現在のより良い方法

開発中にこのような要件に遭遇したので、将来使用するために記録しました。需要背景キーボード ショートカ...

JavaScript関数におけるこのポイントの問題の詳細な説明

このキーワードどのオブジェクトが関数を呼び出しますか? また、関数内の this はどのオブジェクト...

WeChatアプレットで数字当てゲームを実装する実際のプロセス

目次機能紹介レンダリング1. ホームページレンダリング用のコード(index03) 2. ゲーム開始...

jsは前のページに戻り、コードを更新します

1. Javascript は前のページ history.go(-1) に戻り、2 つのページを返し...

mysql ビュー関数の分析と使用例

この記事では、例を使用して MySQL ビューの機能と使用方法を説明します。ご参考までに、詳細は以下...

本をめくる効果を実現するネイティブJS

この記事では、ネイティブ JS で実装された本をめくる効果の図を紹介します。効果は次のとおりです。 ...

MySQLデータベースのマスタースレーブ同期構成と読み取り書き込み分離

MySQL マスター スレーブ レプリケーションを使用する利点は次のとおりです。 1. 安定性を向上...

jQueryとCSSを組み合わせてトップに戻る機能を実現

CSS操作 CS $("").css(名前|プロ|[,値|関数]) 位置$(&q...