特定の親要素を持つ子要素だけcssを当てない方法

※本記事のコードは参考用です。使用前にご自身で動作確認をお願いします。

特定の親要素に基づいて、その子要素にスタイルを適用したくない場面はよくあります。

実際、このブログを作成する際、<pre>タグ内の<code>要素にはスタイルを適用したくない状況が出たので、それについての備忘録です。

:notセレクタを使った例

:not()擬似クラスを使うと、特定の要素を除外してスタイルを適用することができます。

/* pre要素の外にあるcode要素だけにスタイルを適用する */
:not(pre) > code {
  background-color: #f0f0f0;
  padding: 0.2em 0.4em;
  border-radius: 4px;
}

この方法では、「直近の親がpreではないcode」にだけスタイルが適用されます。

ポイントは、not(pre) > code子セレクタに指定することです。

なぜ:not(pre) codeではだめなのか?

preの中にあるcode全てに適用したいから、:not(pre) codeだと思いがちですが、これだと意図しない挙動になってしまいます。

たとえば、以下のHTMLを見てください。

<div>
  <pre>
    <code>これはpre内のコードです</code>
  </pre>
</div>

この場合、divはpreではないので、:not(pre)にマッチしてしまい、divの中にあるcodeにスタイルが当たってしまいます。

つまり、たとえpre内にあるcodeだとしても、スタイルが適用されてしまい、「pre内のcodeにはスタイルを当てたくない」という目的とズレてしまいます。

all: unsetを利用した例

preは中にdivなどのブロック要素をいれることができませんが、例えば以下のようにcodeがpreの孫要素だとしてもスタイルを当てたくない場合、:not()だと指定が難しいです。

<pre>
  <span>
    <code>これはpre内のコードです</code>
  </span>
</pre>

:not()セレクタでは「親がpreじゃない」ことしか見れないため、孫要素(間に何かが挟まっている場合)まで正確に除外するのは難しいです。

そのため、確実に「pre内のcodeにはスタイルを当てたくない」場合は、all: unsetを使う方法が有効です。

all: unsetは要素に適用されているすべてのスタイルをリセットするcssプロパティです。

code {
  /* まずすべてのcodeにスタイルを適用 */
  background-color: #f0f0f0;
  padding: 0.2em 0.4em;
  border-radius: 4px;
}
pre code {
  all: unset; /* preの中にあるすべてのcodeはリセットする */
  background-color: #000;
}

* 一旦code全部にスタイルを当てる

* そのあと、pre配下のcodeをリセットする

ただし、「親から継承されるはずのプロパティ」などもリセットされる強力なプロパティなので、使い所にはかなり注意が必要です。

## まとめ

以上、特定の親要素を持つ子要素だけcssを当てない方法について考察してきました。

デモページをご用意しましたので、ぜひ参考にしてください。

目的にあった手段をうまく選んでいきましょう。