導入
CSSプリプロセッサを使ったことがあるフロントエンド開発者なら、おそらくネスト機能に遭遇したり、使ったりしたことがあるでしょう。これは非常に人気のある機能で、私にとってはCSSプリプロセッサを使うきっかけの一つとなりました。.
今年、Chrome、Firefox、Safariといった主要ブラウザすべてでネイティブCSSネストがサポートされました。これはCSSの記述を容易にするCSSのコア機能です。この記事では、CSSネストについてこれまでに学んだことをまとめ、その成果をユースケースや例とともに皆さんと共有したいと思います。.
あなたの熱意と集中力以外に従うべき前提条件はありません。.
CSSのネスト機能は、多くの開発者にとって待望の機能でした。以前はSassやLessといったCSSプリプロセッサに頼っていました。簡単に概要を説明しましょう。
次の例を考えてみましょう。.nav__item セレクターにアイコンがあります。.
.nav__item {
.icon {
display: flex;
padding: 1rem;
}
}上記のコードは有効なSassコードです。コンパイルすると、ブラウザでは次のように表示されます。
.nav__item .icon {
display: flex;
padding: 1rem;
}ネイティブCSSネストでは、同じCSSがそのまま機能します。ネイティブCSSネストとブラウザのDevToolsの比較を示す図を以下に示します。.
ブラウザが CSS を CSS での表示とほぼ同様に表示することに注目してください。.
この CSS が Sass にコンパイルされた場合、ブラウザには次のように表示されます。
CSSネストの利点
私の意見では、ネストされた CSS が有用である正当な理由がいくつかあります。
- CSS が読みやすくなります。.
- スタイルをグループ化する
- 特定のスタイルを制限する
- クラスや ID を持たない HTML 要素のスタイル設定。.
CSSネストルール
CSS ネストについて理解を深めるために、さまざまな CSS の問題と、ネストによってそれらの問題がどのように解決できるかを視覚的に説明する例を示します。.
まず、アンパサンド記号「&」について学ぶ必要があります。この記号が不可欠な状況がいくつかあります。.
クラスやIDなしで要素をネストする
この例では、要素 <a> .nav__item でスタイル設定されています。CSS を有効にするには、<head> マークの使用は任意です。.
.nav__item {
& a {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item a {
}チェックマークをオプトアウトすることもできます。
.nav__item {
a {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item a {
}これは最近のアップデートで、「Relaxed CSS nesting」と呼ばれています。最新のChrome CanaryとSafari Technology Previewで動作します。Adam ArgyleによるRelaxed Nestingに関するこちらの投稿をご覧ください。.
クラスを使用して要素をネストする
前と同じ例を考えてみましょう。ただし、要素 <a> HTML クラスがあります。.
.nav__item {
.link {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item .link {
}ここではシンボルを使う必要はありません。クラス名だけで十分です。.
CSSコンバイナのネスト
CSSネイティブネストの利点の一つは、コンビネータを使用できることです。いくつか例を見てみましょう。.
以下の例では、.nav__item クラスを持つ要素のうち、同じクラスを持つ別の要素が先行する要素を選択したいと考えています。この目的のために、隣接兄弟セレクタを使用しました。.
ネイティブCSSのネストでは、アンパサンド記号を使ってこれを模倣できます。アンパサンド記号を2回繰り返していることに注目してください。.
.nav__item {
& + & {
border-left: 2px solid;
}
}
魔法はアンパサンドの2回目の繰り返しで起こります。ここでブラウザは、私が隣接兄弟セレクタを使いたいと考えていることを認識します。これを示す図をお見せしましょう。
ネスト構造のもう一つの例は、childコンビネータです。これは要素の直接の子要素を選択できます。.
.nav__item {
> a {
padding: 1rem;
}
}アンパサンド記号
.nav__item {
& a {
color: blue;
}
}これは元のCSSネスト仕様では必須でした。Safari TP 179以降およびChrome Canary 120では、ネストされた要素にアンパサンドは不要になりました。.
その結果、次のようになります。
.nav__item {
a {
color: blue;
}
}唯一の問題は、マークアップとマークアップを含む以前のバージョンの仕様に戻す必要があることです。.
ネストの例: Active、Focus、Hover
:active、:focus、:hover は、ユーザーのアクションによってアクティブ化される CSS 疑似クラスです。.
CSSネストを使えば、コードの重複を避けるために一度に全てをネストすることができます。:hover を例に挙げてみましょう。
button {
&:hover {
background-color: var(--bg-color);
}
&:focus {
outline: solid 2px;
}
}ネスト用のプリプロセッサを使用する場合の違いは、ブラウザが次のようにレンダリングすることです。
button:hover {
background-color: var(--bg-color);
}
button:focus {
outline: solid 2px;
}Chrome、Safari、Firefox で CSS ネスト がどのように表示されるかを見てみましょう。.
CSS ネストに関する DevTools UX についてはいくつか考えがあり、それについてはこの記事の後半で取り上げたいと思います。.
ネストの例: コンテンツの投稿
ネストされたCSSをテストする最初の例の一つは、投稿本文のスタイル設定です。見出し、テキスト、画像、引用文などを含む記事を想像してみてください。.
見出し
私たちはタイトルを次のようなスタイルにする傾向があります:
.post-content h1,
.post-content h2,
.post-content h3,
.post-content h4 {
/* styles here */
}ネストされた CSS を使用すると、簡単になります。
.post-content {
h1,
h2,
h3,
h4 {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}:is() セレクターを使用して同じことを行うこともできます。.
.post-content {
:is(h1, h2, h3, h4) {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}段落要素
よくあるケースとしては、段落内にあるリンクのスタイル設定が挙げられます。このような場合、CSSのネストが非常に効果的です。.
.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
}
}
}リンクにはホバー効果やフォーカス効果も必要になる場合があります。.
.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
&:hover {
/* hover styles */
}
}
}
}メディアクエリをネストすることもできます。.
.post-content {
& p {
/* base styles */
@media (min-width: 400px) {
/* do something */
}
}
}場合によってはCMSが要素となることもある <p> 別の要素で囲みます。スタイル上の理由から、直接の要素にのみ使用してください。 <p> スタイルを整える。.
.post-content {
/* Select the direct <p> elements */
> p {
/* base styles */
}
}ブロック引用
この例では、引用文に独自のカスタムスタイルが適用され、要素 <p> 引用内で、下余白をゼロにリセットすることを選択します。.
.post-content {
& blockquote {
/* custom quote styling */
& p {
margin-bottom: 0;
}
}
}ポスト形状
投稿フォームには画像と
私の例では、
.post-content {
& figure {
& img {
/* the figure's image styles */
}
/* changes to the <figure> container, if it has a figcaption element */
&:has(figcaption) {
display: flex;
align-items: start;
}
& figcaption {
/* caption styling */
}
}
}投稿一覧
最後の項目を除くすべてのリスト項目に境界線を追加する必要があります。そのために、:not()セレクタを使用しました。.
.post-content {
li {
&:not(:last-child) {
border-bottom: 1px solid;
}
}
}:not() を使用するには、その前にアンパサンドを追加する必要があります。.
見出しのカスタム間隔
車間距離は <h3> そして <h4> そのうちの 1 つの後にコード スニペットが続く場合は削減します。.
.post-content {
& h3 + [class*="language-"],
& h4 + [class*="language-"] {
margin-top: 0.5rem;
}
}この実際の例で見たように、CSS ネストの使用は、特に CSS プリプロセッサの経験があれば簡単です。.
ネストの例: カードコンポーネント
CSS ネストを使用して目的のスタイルを実現するシンプルなカード コンポーネントを紹介します。.
デフォルトまたは基本スタイルを持つ .card 要素があると仮定して、ネストされた CSS の使用方法を説明します。.
.card {
/* default card styles */
}
コンテナクエリのネスト
コンテナの幅が 400 ピクセルより大きい場合、カードをフレキシブル コンテナに変換します。.
.card {
/* default card styles */
/* if the container width is 400px or bigger */
@container card (min-width: 400px) {
display: flex;
}
}段落要素のスタイル設定
段落要素を次のように使用したい <h3> この方法では、要素にマージンとパディングを適用できます。 <p> 追加します。これがないと、UIに余分なスペースがなくなります。.
.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
}コンテナの幅が 400 ピクセル以上の場合は、.card__content 要素もフレキシブル コンテナに変換する必要があります。.
.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
@container card (min-width: 400px) {
display: flex;
flex-direction: column;
justify-content: center;
}
}ネストの例: フォーム入力
よくあるケースとしては、入力プレースホルダーのスタイル設定が挙げられます。問題は、ブラウザベンダーごとに独自のプレフィックスが付けられていることです(ああ、今は2023年ですからね)。.
プレフィックス スタイルにはコロンが必要なので、& 記号を使用する必要があります。そうしないと、スタイルが壊れてしまいます。.
input {
--placeholder-color: #969696;
/* other styles */
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
&::-moz-placeholder {
color: var(--placeholder-color);
opacity: 1;
}
&:-moz-placeholder {
color: var(--placeholder-color);
}
}ネストされた CSS を使用することと、ネストされた CSS を使用せずにプレフィックス スタイルを直接記述することの違いは何かと疑問に思うかもしれません。.
/********** Option 1: native nesting **********/
input {
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
}
/********** Option 2: without nesting **********/
input::-webkit-input-placeholder {
color: var(--placeholder-color);
}これら2つに違いはありません。どちらも同じ特性(0, 1, 1)を持ちます。.
ネストの例: 親要素を介した要素のスタイル設定
CSSのネスト構造を使うことで、子要素の位置に応じてスタイルを変更できます。例えば、.button要素が.box親要素内に存在する場合、その要素は全幅を占める必要があります。.
<div class="box">
<h2>Get access to all features</h2>
<p>Create an account now and get access to all exclusive features.</p>
<a href="/offer" class="button">Create an account</a>
</div>.button {
.box & {
width: 100%;
}
}
/* equivalent to */
.box .button {
}CSSネストを探索中に見つけたバグ
符号なしグローバルセレクタの使用
例えば、カードがあり、その中にあるすべての要素を選択したいとします。CSSネイティブネストを使えば、以下のように記述できます。
.card {
* {
/* styles here */
}
}これは Chrome Stable では動作しないことに気づきましたが、Chrome Canary 121、Safari 17.1、Firefox 119 では正常に動作します。.
解決策は句読点を追加することです。.
.card {
& * {
/* styles here */
}
}符号なしデータ属性の使用
この問題では、チェックマークのないデータ属性を選択しても、期待どおりの結果が得られません。.
.card {
[data-type="featured"] {
/* styles here */
}
}Chrome Stable では動作しないことに気づきましたが、Chrome Canary 121、Safari 17.1、Firefox 119 では正常に動作します。.
これを修正するには、コンマを追加する必要があります。
.card {
&[data-type="featured"] {
/* styles here */
}
}これらのバグは両方とも、Chrome Canary の緩和された CSS ネストのリリースで修正されました。.
CSSネストのサポートの識別
@supports は CSS のネストがサポートされているかどうかを確認するために使用できます。今回のケースでは、ブラウザがアンパサンドを認識するかどうかを確認します。.
@supports selector(&) {
.post-content {
& h2 {
/* styles here. */
}
}
}Bramus によるこの Codepen で、サポートを識別するための他のオプションを調べることができます。.
今日は、ネストされたCSSを通常のCSSにコンパイルするPostCSSネスティングプラグインを使用します。安全に使用できるようになりましたら、このプラグインを削除します。.
CSS ネストのための DevTools UX
私はブラウザの DevTools における CSS ネストに関する現在の UX があまり好きではありません。.
私は別の記事で、DevTools で CSS ネストをどのように実現したいかについていくつかの提案を検討しました。.
結果
CSSネストは、CSSの記述方法を改善する重要な機能です。現在、ネストの使用は可能ですが、サポートがまだ新しいため、ユーザーへの配慮が必要です。.
























