カスケードレイヤー「@layer」でCSSの実装がどう変わるのか、仕組みと基礎知識、さまざまな使用例を徹底解説
Post on:2022年3月3日
CSSの新機能「カスケードレイヤー」がいよいよ主要ブラウザすべてにサポートされます。Firefox 97(先月リリース)とChrome 99(3/1リリース)でサポートされ、そしてSafariでは次期バージョンでサポートされる予定です。
カスケードレイヤー@layer
を使用すると、CSSの詳細度とスタイルの順番をカスケード内で明示的にレイヤー化(階層化)でき、これまでのCSSの実装方法が大きく変わります。
カスケードレイヤーの仕組みと基礎知識、さまざまな使用例を紹介します。
Hello, CSS Cascade Layers
by Ahmad Shadeed
CSSのカスケードレイヤーについて知識を得たい人は、下記の記事もお勧めします。
- CSSの新機能カスケードレイヤー「@layer」CSSをレイヤー化して扱え、今までの実装方法が大きく変わる!
- CSSの新機能カスケードレイヤーが主要ブラウザにサポートされます、最初に理解しておきたい基礎知識を解説
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- CSSでよくある問題
- CSSの新機能「カスケードレイヤー」とは
- サポートブラウザ
- レイヤーはカスケードのどこにありますか?
- カスケードレイヤーの使用例
- カスケードレイヤーについてさらに詳しく
- 終わりに
はじめに
CSSでよくある混乱の原因の1つは、スタイルを定義する際の詳細度です。たとえば、ある要素のdisplay
値を変更しても、カスケード内の別の要素がより高い詳細度を持っているとオーバーライドされて、うまく機能しないことがあります。あるいは、別の要素に!important
があるなどです。コードの量が増え、このような問題を防ぐ(あるいは減らす)方法でCSSを管理していない場合に起こります。
カスケードと詳細度の問題との戦いを克服するためには、特定のCSSブロックをどこに書くのか注意する必要があります。小さなプロジェクトなら簡単かもしれませんが、大規模なプロジェクトでは時間のかかる作業です。その結果、CSSをうまく管理して、その結果カスケードの問題を防ぐ(あるいは減らす)ためのさまざまな方法が見られるようになりました。私が思い浮かべたのは、BEM(Block, Element, Modifier)、Jonathan Snook氏のSmacss、Harry Roberts氏のInverted Triangle CSSの3つです。
この記事ではカスケードレイヤーの仕組み、カスケードレイヤーでどのようにCSSを安心して書けるようになるのか、実際の使用例とともに解説します。
CSSでよくある問題
CSSの新機能「カスケードレイヤー」を使用する大きな利点は、詳細度や記述の順番を気にせずにCSSを記述できることです。例を挙げてみましょう。
2つのスタイルを持つボタン
デフォルトとghostの2つのスタイルを持つボタンがあります。HTMLは、非常にシンプルです。
1 2 3 4 |
<footer class="form-actions"> <button class="button">Save edits</button> <button class="button button--ghost">Cancel</button> </footer> |
もちろん、上記のHTMLはうまく機能します。しかし、3つ目のスタイルが必要になり、.button
宣言の後にそれを記述できない場合はどうすればよいでしょうか。
3つのスタイルを持つボタン
.button
が.button--facebook
の後にあるため、.button--facebook
のスタイルはオーバーライドされてしまいます。
.button
にオーバーライドされないようにするには、.button--facebook
の詳細度を高くすることで回避できます。
1 2 3 4 |
.some-parent .button--facebook { background-color: var(--brand-fb); color: #fff; } |
もしくは下記でも回避できます(が、お勧めしません)。
1 2 3 4 |
.button--facebook { background-color: var(--brand-fb) !important; color: #fff !important; } |
どちらの解決方法も、それほど良いものではありません。ベストな方法は、.button
宣言の直後の正しい場所に記述することです。CSSプリプロセッサ(例えばSassなど)の助けを借りて、CSSファイルをパーシャルとコンポーネントに分割せずに行うのは簡単な仕事ではありません。
CSSの新機能「カスケードレイヤー」とは
カスケードレイヤーとは、大規模なプロジェクトでCSSを記述する際にデベロッパーがより管理しやすくするためのCSSの新機能です。仕様の作成者であるMiriam Suzanne氏によると、カスケードレイヤーの機能は以下の通りです。
カスケードレイヤーは、詳細度のヒューリスティックやソースの順番に完全に依存することなく、内部のカスケードロジックを管理できるようにします。
前述の例にカスケードレイヤーを適用してみましょう。
最初にレイヤーを定義します。 @
の後にレイヤー名を記述するだけです。
1 |
@layer components { } |
components
というレイヤーを定義しました。そのレイヤーの中に、デフォルトのボタンスタイルを記述します。
1 2 3 4 5 6 |
@layer components { .button { color: #fff; background-color: #d73a7c; } } |
次に、バリエーション用のレイヤーを用意し、同様にスタイルを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@layer components { .button { color: #fff; background-color: #d73a7c; } } @layer variations { .button--ghost { background-color: transparent; color: #474747; border: 2px solid #e0e0e0; } } |
下記はレイヤーの概念を視覚化したものです。
CSSでは最後に定義されたものがレイヤーリストの最初になるので、Photoshopのレイヤーと似ています。
レイヤーの概念
この例では、variation
レイヤーが最後に定義されているので、components
レイヤーよりも優先(オーバーライド)されます。
また、どのレイヤーを優先するかは記述の順番だけでなく、最初に優先度を定義する方法もあります。
1 |
@layer components, variations; |
前述の例に戻ります。
最初の問題は、ボタンの別のバリエーションを作成する必要がありましたが、バリエーションボタンの詳細度が低くなる場所に記述してしまったことです。カスケードレイヤーを使用すると、variations
レイヤーにCSSを記述することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@layer components, variations; @layer components { .button { color: #fff; background-color: #d73a7c; } } @layer variations { .button--ghost { background-color: transparent; color: #474747; border: 2px solid #e0e0e0; } .button--facebook { background-color: var(--brand-fb); } } |
これで、ベースのスタイルよりもコンポーネントのバリエーションが常に優先されるようにすることができます。
上記の説明を視覚的に見てみましょう。
レイヤーパネルで、各ボタンがどのようにレイヤー内で機能するかに注目してください。順番は上部にある@layer
の定義に従っています。
レイヤーの概念: ブルーになる
上部の@layer
で順番を変更すると、components
レイヤーがvariations
より優先されます。その結果、デフォルトのボタンスタイルにオーバーライドされます。
@layer
でレイヤーの順番を変更: デフォルトのレッドになる
レイヤーにスタイルルールを追加する
カスケードレイヤーでは、ブラウザは同じ@layer
定義のスタイルを組み合わせて、その順番に従って一度に読み込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@layer components, variations; @layer components { .button {..} } @layer variations { .button--ghost {..} } /* 500行後 */ @layer variations { .button--facebook {..} } |
上記のCSSの場合、ブラウザはvariations
レイヤーの.button--ghost
の直後に.button--facebook
を追加することになります。
下記は、この概念を視覚化したものです。
レイヤーの概念
サポートブラウザ
サポートしているブラウザは、CSSの新機能を考える上で最も重要な問題です。この記事の執筆時点で、Firefox、Chrome、Safari TPでサポートされています。
【訳者注】2月にリリースされたFirefox 97ではデフォルトでサポートされ、3/1にリリースされたChrome 99でもサポートされました。Safariは次期バージョンでサポートされる予定です。
参考: Firefox, Chrome, Safari
カスケードレイヤーのサポートブラウザ
※3/2のキャプチャですが、Chromeはまだ反映されていないようです。
拡張機能として使用できますか?
いいえ、できません。JavaScriptのポリフィルを使用しない限り(まだないです)。
レイヤーはカスケードのどこにありますか?
その疑問に答えるために、CSSカスケードの概要を見てみましょう。
CSS Cascadeは、以下のように順序付けられます(高いものほど優先されます)。
- Origin and Importance(宣言の出自と
!important
) - Inline Styles(インラインスタイル)
- Layer(レイヤー)
- Specificity(詳細度)
- Order of appearance(記述の順番)
下記の図は線が太く濃いほど、そのスタイルがカスケードでより優先されることを意味します。
CSSカスケードの概要
Origin and Importance(宣言の出自と!important
)
スタイルルールの出自と重要性は異なるもの(しかし関連しています)なので、それぞれについて解説します。
スタイル ルールのOrigin(出自)は優先順位の高い順に、以下のいずれかになります。
- デベロッパーによるスタイル
- ユーザーによるスタイル
- ブラウザによるスタイル
つまり、デベロッパーが作成したCSSは、常にユーザーとブラウザのスタイルに優先されます。
例を見てみましょう。
1 2 3 |
html { font-size: 16px; } |
ユーザーがブラウザのデフォルトのフォントサイズを変更しようとした場合、上記のCSSはユーザーの設定をオーバーライドします(デベロッパーのスタイルがユーザーのスタイルに勝つため)。
ユーザーの設定したスタイルをオーバーライドする
これはアクセシビリティにとって悪い使用例です。実際のプロジェクトでは行わないでください。スタイルの出自を説明するために提示したものです。
ブラウザのスタイルとは、UAスタイルシートです。たとえば、<button>
のデフォルトのスタイルは各ブラウザごとに異なります。そしてデベロッパーのスタイルがブラウザのスタイルに勝つため、デフォルトのスタイルをオーバーライドすることができます。
<button>
をデベロッパーツールで調べると、UAスタイルシートによりデフォルトのスタイルが適用されていることが分かります。
<button>
のスタイルを調べる
上記はすべて通常のルールです。つまり、!important
というキーワードがないという意味です。もしある場合は、次のような順番になります。
- ブラウザによるスタイル(
!important
あり) - ユーザーによるスタイル(
!important
あり) - デベロッパーによるスタイル(
!important
あり) - デベロッパーによるスタイル(通常)
- ユーザーによるスタイル(通常)
- ブラウザによるスタイル(通常)
Inline Styles(インラインスタイル)
要素にインラインスタイルがある場、同じ重要度を持つ兄弟の中で最も高い詳細度を持つことになります。
下記のHTMLとCSSはインラインスタイルが優先されるため、<button>
のカラーは#fff
になります。
1 |
<button style="color: #fff;">Send</button> |
1 2 3 |
button { color: #222; } |
Layer(レイヤー)
そして、レイヤーです!
これはカスケードの新しいお客さまです。カスケードレイヤーは、セレクタの詳細度よりも優先されます。下記の例で、カスタムレイヤーのp
要素のフォントサイズはどうなると思いますか?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@layer base, custom; @layer base { #page .prose p { font-size: 1rem; } } @layer custom { p { font-size: 2rem; } } |
フォントサイズは2rem
です。カスケードレイヤーでは要素の詳細度に関係なく、次のレイヤでオーバーライドされる場合は無視されます。
Specificity(詳細度)
レイヤーの後にブラウザはCSSのルールを確認し、セレクタの詳細度に基づいてどちらが勝つか判断します。
下記は簡単な例です。
.newsletter .button
は、.button
よりも高い詳細度を持っています。その結果、.button
のスタイルは.newsletter .button
のスタイルにオーバーライドされます。
1 2 3 4 5 6 7 |
.button { padding: 1rem 1.5rem; } /* こちらが勝ち */ .newsletter .button { padding: 0.5rem 1rem; |
Order of appearance(記述の順番)
最後に、記述の順番が実行されます。2つの要素の詳細度が同じ場合、CSSドキュメント内での順番によって、どちらが勝つかが決まります。
1 2 3 4 5 6 7 8 |
.newsletter .button { padding: 1rem 1.5rem; } /* こちらが勝ち */ .newsletter .button { padding: 0.5rem 1rem; } |
上記のルールはどちらも同じ詳細度です。しかし、.newsletter .button
の方が後に記述されているので、勝ちます。
レイヤーがカスケードの中でどのような位置づけにあるのかがわかったところで、カスケードレイヤーの使用例を見てましょう。
カスケードレイヤーの使用例
カスケードレイヤーが実際のプロジェクトで輝ける場所はどこだろうと考えてみたところ、次の用途を思いつきました。
UIテーマの切り替え
私が取り組んでいるプロジェクトでは、UIテーマの設定にカスケードレイヤーを使用することが完璧なソリューションになります。ここで解決される問題は、デベロッパーである私がCSSを変更することなくテーマを切り替えられるようになること、あるいは何らかの方法で並び替えができるようになることです。
1 |
@layer base, elements, objects, components, pages, themes; |
CSSにはさまざまなレイヤーがあり、最後にthemes
レイヤーがあります。そして、themes
レイヤーには複数のレイヤーを入れ子にすることができます(カスケードレイヤーはネストをサポートしています)。
themes
レイヤー内で最初に@layer custom, default
を定義していることに注目してください。これでdefault
はcustom
をオーバーライドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@layer base, elements, objects, components, pages, themes; @layer themes { @layer custom, default; @layer default { :root { --color-primary: #1877f2; } } @layer custom { :root { --color-primary: #d73a7c; } } } |
UIテーマを切り替えたい時は、@layer themes
内の最初の定義でレイヤーを並べ替えだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@layer base, elements, objects, components, pages, themes; @layer themes { /* customを優先させる */ @layer default, custom; @layer default { :root { --color-primary: #1877f2; } } @layer custom { :root { --color-primary: #d73a7c; } } } |
サードパーティのCSS
カスケードレイヤーは、サードパーティのCSSにも便利です。たとえば、flickityのカルーセルを例に見てましょう。!important
がたくさん使用されています。
1 2 3 4 5 6 7 8 9 10 11 12 |
.flickity-page-dots { bottom: 20px !important; } .flickity-page-dots .dot { background: #fff !important; opacity: 0.35 !important; } .flickity-page-dots .dot.is-selected { opacity: 1 !important; } |
カスケードレイヤーを使用すると、コンポーネントレイヤーの前にサードパーティーのCSSを追加することができます。外部CSSファイルをインポートして、レイヤーに割り当てることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@layer base, vendors, components; @layer base { /* ベースのスタイル */ } /* .cssファイルをインポートしてレイヤーに割り当てる */ @import url(flickity.css) layer(vendors); @layer components { .flickity-page-dots { bottom: 20px; } .dot { background: #fff; opacity: 0.35; } .dot.is-selected { opacity: 1; } } |
詳細度の問題を心配する必要がなくなる
リストのコンポーネントがあり、リストのマージンが小さいバリエーションが必要だとします。
1 2 3 4 |
<ul class="list"> <li class="list__item list__item--compact">Item 1</li> <!-- Other items --> </ul> |
:not
疑似セレクタは要素の詳細度を高くするため、:not
を再利用しないとオーバーライドできません。
1 2 3 4 5 6 7 8 9 |
/* こちらが勝ち */ .list__item:not(:last-child) { margin-bottom: 2rem; outline: solid 1px #222; } .list__item--compact { margin-bottom: 1rem; } |
上記のCSSでは.list__item--compact
は、.list__item
をオーバーライドしません。.list__item
には:not
があり、詳細度が高いためです。これを機能させるには、下記のように記述しなければなりません。
1 2 3 4 5 6 7 8 |
.list__item:not(:last-child) { margin-bottom: 2rem; outline: solid 1px #222; } .list__item--compact:not(:last-child) { margin-bottom: 1rem; } |
この問題をカスケードレイヤーで解決してみましょう。
@layer list
レイヤーにbase
とoverrides
を入れ子にします。overrides
にはバリエーションのスタイルを記述し、overrides
が後に記述されているので期待通りに動作します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@layer list { @layer base, overrides; @layer base { .list__item:not(:last-child) { margin-bottom: 2rem; } } @layer overrides { .list__item--compact { margin-bottom: 1rem; } } } |
ネストされたコンポーネント
メインのソーシャルフィードアイテムに対するアクション(いいね、コメント)のリストと、各コメントごとに別のリストがあります。
ネストされたコンポーネント
アイコンのサイズはフィードでは24px
で、コメントではサイズが小さくなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@layer feed, comments; @layer feed { .feed-item .c-icon { width: 24px; height: 24px; } } @layer comments { .comment__icon { width: 18px; height: 18px; } } |
.feed-item .c-icon
が、.comment__icon
よりも詳細度が高いことに注目してください。これはカスケードレイヤーを使用する利点です。
ユーティリティCSS
ユーティリティのCSSクラスには、常に要素に適用されるように!important
を付けることに慣れてきたかもしれません。しかし、カスケードレイヤーを使用すれば、ユーティリティを最後に配置することができます。
たとえば、ユーティリティクラス.px-0
を持つヘッダがあり、このクラスでパディングの左右を0
にリセットしたいとします。
1 2 3 |
<div class="c-page-header px-0"> <!-- Content --> </div> |
カスケードレイヤーを使用すれば、詳細度を気にせず、!important
も付けずに記述できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@layer base, vendors, components, utils; @layer components { @layer page-header { .c-page-header { padding: 1rem 2rem; } } } @layer utils { .px-0 { padding-left: 0; padding-right: 0; } } |
カスケードレイヤーについてさらに詳しく
レイヤー化されていないスタイルは詳細度がより高い
レイヤー化されていないCSSのスタイルがある場合、暗黙的に最後のレイヤーに追加されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.button { border: 2px solid lightgrey; } @layer base, components; @layer base {/* Base styles */} @layer components { .button { border: 0; } } |
上記のCSSでは、.button
ルールが@layer
なしで定義されており、ブラウザにとってこの.button
ルールは暗黙的にレイヤーに配置されることになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@layer base, components; @layer base {/* Base styles */} @layer components { .button { border: 0; } } /* 暗黙のレイヤー */ @layer { .button { border: 2px solid lightgrey; } } |
終わりに
カスケードレイヤーはCSSのエキサイティングな機能です! この記事で見たように、かなり便利に使うことができます。私にとっての唯一の制約は、CSSだけでは拡張機能として使用できないことです。そのため、Webコミュニティでレイヤーの採用は少し遅れるかもしれません。
関連リソース
- The Future of CSS: Cascade Layers
- Getting Started With CSS Cascade Layers
- Cascade layers are coming to your browser
- CSSの新機能カスケードレイヤー「@layer」CSSをレイヤー化して扱え、今までの実装方法が大きく変わる!
- CSSの新機能カスケードレイヤーが主要ブラウザにサポートされます、最初に理解しておきたい基礎知識を解説
この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors