CSSの「否定」を制する者は、DOMの複雑さを制す:`:not()` 擬似クラスの極意
やあ。現場でCSSと格闘していると、時々どうしようもなく「あぁ、これ以外の全部にスタイルを当てたいんだよ!」と叫びたくなる瞬間があるだろう?
例えば、リストの最後の要素だけ余白を消したいとか、特定のクラスが付いていないボタンにだけホバーエフェクトを付けたいとか。そんな時、多くのエンジニアは「スタイルを当ててから、後で打ち消す」という泥臭い上書きをやりがちだ。だが、その書き方はCSSの肥大化と保守性の低下を招く最大の要因の一つだと言える。
今日は、そんなストレスから君を解放してくれる「`:not()` 擬似クラス」について、実務の現場で培った「本当に賢い使い方」を伝授しようと思う。
—
`:not()` がブラウザの裏側でやっていること
まず、仕組みを理解しておく必要がある。`:not()` は「否定擬似クラス」と呼ばれ、カッコ内に指定したセレクタに合致しない要素をターゲットにする。
ブラウザのレンダリングエンジンは、DOMツリーを走査する際、この `:not()` を見つけると「除外リスト」を作成する。CSSのセレクタは一般的に「右から左」へと解析されるが、`:not()` が含まれている場合、その条件を満たさないノードを効率的にスキップする仕組みになっている。
重要なのは、`:not()` 自体はセレクタの「詳細度(Specificity)」を上げないということだ。`:not()` の中に書いたセレクタの詳細度が、そのまま計算対象になる。ここを勘違いして「`:not()` を使えば詳細度がリセットされる」と誤解していると、後で痛い目を見るぞ。
—
実務で輝く `:not()` のパターン
現場でよくある「除外したい」ケースを、綺麗に解決するコードを紹介しよう。
1. 「最後以外」に margin を適用する(定番のベストプラクティス)
昔は `margin-right: 10px` を当ててから、最後に `margin-right: 0` で打ち消していたはずだ。今の時代、そんな無駄なことはやめよう。
/ 最後の要素以外に右マージンを適用 /
.list-item:not(:last-child) {
margin-right: 16px;
}
/
- これなら「打ち消し」のコードが不要になり、
- DOMの構成が変わってもスタイルが崩れにくい。
/
2. 特定のクラスを除外したスタイル適用
「プライマリーボタン以外の全ボタンに枠線を付ける」といったケースだ。
/ .btn-primary ではない全ての .btn にスタイルを当てる /
.btn:not(.btn-primary) {
border: 1px solid #ccc;
background-color: transparent;
}
/
- 複雑なUIコンポーネントを作る際、例外を除外するだけで
- if文的なロジックをCSSで簡潔に書ける。
/
—
知っておくべき「落とし穴」と進化
`:not()` を使う上で、中級者以上が必ずぶつかる壁がいくつかある。
- `:not()` のネストは非推奨: `:not(:not(…))` のような書き方は、ブラウザによって挙動が怪しくなることがあるし、何よりコードが読みづらい。CSSの可読性は正義だ。
- 疑似要素は除外できない: `:not(::before)` のように、疑似要素を引数に取ることは仕様上できない。ここは潔く別の方法を考えよう。
- `:is()` や `:where()` との組み合わせ: 最近のモダンブラウザでは、`:not()` の引数にカンマ区切りで複数のセレクタを渡せるようになっている(例:`:not(.a, .b)`)。さらに `:is()` と組み合わせると、信じられないほど記述量が減る。
/ .is-disabled や .is-hidden ではない要素だけを対象にする /
.card:not(.is-disabled, .is-hidden) {
cursor: pointer;
transition: transform 0.2s ease;
}
—
シニアからのアドバイス:CSSは「引き算」で考える
CSSを組むのが下手なエンジニアは、どんどんプロパティを「足し算」していく。結果、コードは上書きの嵐になり、自分でも何が優先されているのか分からないスパゲッティコードが出来上がる。
一方で、優れたエンジニアは「どうすればデフォルトの状態で美しく見えるか」を考え、`:not()` のような否定形を駆使して「例外を最小限にする」ことに注力する。
「上書き」するのではなく、「最初から当てない」こと。
この視点を持つだけで、君の書くCSSは劇的にクリーンになるはずだ。
もし今日、君のプロジェクトで `margin-right: 0` や `color: inherit` のような「打ち消し」の行を見つけたら、その箇所こそが `:not()` を導入する絶好のチャンスだと思ってほしい。
現場からは以上だ。また何か躓くことがあれば、いつでも聞きに来るといい。コーディングを楽しんでくれ。

コメント