CSSの特殊なセレクターの書き方使っていますか？

# まえおき
みなさん特殊なCSSのセレクター書いていますか？
`>`・`+`・`~`を使用した指定はよく使うと思います。

今回はあまり触れる機会は少ないけど覚えておくとよさそうなセレクターを紹介していきます。

# 属性セレクター
https://developer.mozilla.org/ja/docs/Web/CSS/Attribute_selectors

こちらを利用することでHTMLのタグにある属性（id,class,hrefなど）の存在・値の有無に対してスタイルをあてることができます。
よくあるのはaタグのhrefの指定によってアイコンを変えたり、
inputのtypeやchecked等状態によって表示を変える場合があります。

基本的にはclassを別途用意してケースに合わせてスタイルをあてるのがベストかと思いますが、臨機応変に使い分けていけると便利かなと思います。

## 属性が存在する場合
```css
p[title] {
  color: red;
}
```

## 一致する場合
```css
input[type="text"] {
  color: red;
}
```

## 始まりに指定した値が含まれる場合
```css
a[href^="https://"] {
  color: red;
}
```

## 終わりに指定した値が含まれる場合
```css
a[href$=".pdf"] {
  color: red;
}
```

## どこかに指定した値が含まれる場合
```css
a[class~="img"] {
  object-fit: cover;
}
```
 
## 大文字小文字を区別
末尾に`i`をつけることで大小区別しません。
```css
a[href*="a" i] {
  color: red;
}
```

区別する場合は`s`をつけます。
```css
a[href*="A" s] {
  color: red;
}
```

## 始まりと終わりが一致する場合
複数指定も可能です。
```css
a[href^="https://"][href$=".pdf"] {
  color: red;
}
```

# :not()
https://developer.mozilla.org/ja/docs/Web/CSS/:not

指定されたセレクターが一致しない場合にスタイルをあてることができます。
　

使用例として、`.pink`が存在する場合はスタイルをあてないようにできます。
```html
<p class="text pink">
    テキストテキスト
</p>

<p class="text red">
    テキストテキスト <!-- このテキストにだけスタイルをあてたい -->
</p>
```

```css
.text:not(.pink) {
  font-size: 22px;
}
```
　
連結することで、どちらか含まないにすることも可能です。
```css
.text:not(.pink):not(.red) {
  font-size: 22px;
}
```

# :is()
https://developer.mozilla.org/ja/docs/Web/CSS/:is

指定されたセレクターが一致する場合にスタイルをあてることができます。

以前は`:matches()`でしたが改名されて`:is()`になりました。

使用例として、`.pink`と`.red`が含まれる`.text`にだけスタイルをあてたい場合は以下のように記述します。
```html
<p class="text pink">
    テキストテキスト
</p>

<p class="text red">
    テキストテキスト
</p>
```

```css
.text:is(.pink,.red) {
  font-size: 22px;
}
```
　
`:is()`を使わない場合と比べて簡易に書けるようになりました。
```css
/* :is()を使わず指定する場合はこう */
.text.pink,
.text.red {
  font-size: 22px;
}
```
       

## :where()
`:is()`と似たなものに`:where()`があります。

https://developer.mozilla.org/ja/docs/Web/CSS/:where

> :where() と :is() の違いは、 :where() は詳細度が常に 0 であるのに対して、 :is() は引数内で最も詳細度の高いセレクターの詳細度を取ります。

CSSは、基本的には上に書いた順に上書きされていきます。
`:where()`による実装は従来通り書いた順に上書きされていきますが、
`:is()`の場合はセレクターの詳細度によって上書きの優先順が変わります。
これらは使用状況やマークアップの構造によって適宜使用をわけていく必要がありそうです。

# :has()
https://developer.mozilla.org/ja/docs/Web/CSS/:has

指定されたセレクターが存在する場合にスタイルをあてることができます。
　
このセレクターの良いところはJavaScriptに頼らず、子要素の存在によって親要素のスタイルを変更できる点です。
例えば`<img>`が動的で存在の有無がわからない場合にスタイルの適用を分けることができます。
```html
<div class="box">
  <p>テキスト</p>
  <img src="hoge.png">
</div>

<div class="box">
  <p>テキスト</p>
</div>
```

```css
.box:has(img) {
  background: red;
}
```
　
 
`:nth-of-type(3)`で絞ればそれ以上の子要素数があった場合にスタイルをあてることもできます。
（JavaScriptを使用せず要素数で絞れるならどこかで使い道はありそう）
```css
/* imgが3つ以上の時は背景を赤色にする */
.box:has(img:nth-of-type(3)) {
  background-color: red;
}
```

## :empty
https://developer.mozilla.org/ja/docs/Web/CSS/:empty

逆に`:empty`を使用すると、子要素が存在しない場合のみスタイルをあてることができます。
```html
<div class="box"><!-- 子要素が存在しない場合にスタイルをあてる --></div>

<div class="box">
  <p>テキスト</p> <!-- こちらは存在するのであたらない -->
</div>
```
```css
.box:empty {
  background: red;
}
```

> 子とは要素のノードまたは文字列 (ホワイトスペースを含む) です。コメント、処理指示、 CSS の content は要素が空であるかどうかの判断には影響しません。

とmozillaにあるように、改行やスペースが入っていると子があると判定されてしまうので注意です。

# さいごに
工夫するとJavaScriptに頼らずCSSのみで解決できるシーンが出てきて僅かながら進化を感じます。
ただ、CSSだけでは不便に感じる個所もあるので、SCSS等を駆使して良いコーディングをしていきましょう。
(次の要素は指定できるのに前の要素指定できないのは不便なので`-`実装してください。お願いします。)