😺

個人的に使用頻度の低い擬似クラスたち

2022/03/07に公開

MDNのデザインが新しくなりましたね。
私としては以前よりも見やすくなっている印象で、大変ありがたく思います。
せっかくのリニューアル記念(?)ということで、サイト内を適当に巡回していたところ、たまたまCSSの擬似クラス一覧にたどり着きました。
どうせならと思い、個人的に使用頻度の低い(もしくは使用したことのない)擬似クラスについてまとめてみました。

擬似クラスとは

そもそも擬似クラスとはなんですかという話です。
ざっくりいうと要素の状態を指定できる便利なやつです。
たとえば:hoverなんかは頻繁に使われる擬似クラスですね。
以下はマウスポインターが(対象の)要素上にある状態の時に、背景色を変化させるコードです。

scss
.box {
  background-color: red;
  &:hover {
    background-color: blue;
  }
}

使用頻度の低い擬似クラスたち

ブラウザに実装されていないものを紹介しても仕方がないので、基本的にはモダンブラウザの最新バージョンである程度実装されているものを対象としています。
具体的にはChrome / Edge / Firefox / Safari / Safari on iOSのうち少なくとも3つ以上のブラウザでサポートされているものです(記事執筆時点)。

:autofill

inputの要素が自動補完された状態を表します。
以下はinputが自動補完された時にborderの色が赤から緑に変わるサンプルです。

scss
input {
  border: 3px solid red;
  &.autofill { // 「autofillあり」の方だけ色が緑に変わる
    &:-webkit-autofill {
      border: 3px solid green;
    }
    &:autofill {
      border: 3px solid green;
    }
  }
}

Tips:背景色を変更する

:autofillでたまにあるのが背景色をデフォルトから変更したい(というよりデフォルトの色を反映したくない)という要望です。
しかしブラウザによっては:autofillにおけるデフォルトのbackground-colorを上書きできないこともあります。
回避策の1つとして、box-shadowを使う方法があります。

scss
input{
  &:-webkit-autofill {
    box-shadow: 0 0 0 2rem green inset; //inset で内側にシャドウを伸ばす
  }
  &:autofill {
    box-shadow: 0 0 0 2rem green inset; //inset で内側にシャドウを伸ばす
  }
}

:indeterminate

一部のフォーム要素で未確定の状態を表します。
対象要素としてはinput[type=checkbox]input[type=radio]progressなどがあります。
以下はチェックボックスとラジオボタンの未定義状態を表したサンプルコードです。
チェックボックスの状態を未確定にするためにはJavaScriptを使う必要があります。

scss
input {
  // 状態が未確定の時は文字が赤色
  &:indeterminate {
    + span {
      color: red;
    }
  }
}
javascript
const checkbox = document.getElementById("checkbox");
// checkboxの場合は、JavaScriptでindeterminateをtrueにする必要がある
checkbox.indeterminate = true;

:placeholder-shown

inputもしくはtextareaにおいて、プレイスホルダーの文字列が表示されている状態を表します。
フローティングラベルを実装する時に便利だったりします。
以下は簡易的なフローティングラベルのサンプルコードです。

scss
input {
  // :focusと組み合わせることで、フローティングラベルの実装に便利
  // :not(:placeholder-shown)でプレイスホルダーが表示されていない(文字列が入力されている)時にラベルを動かす
  &:focus,
  &:not(:placeholder-shown) {
    + label {
      color: rgba(0, 0, 0, 0.7);
      transform: translate(-0.1rem, -0.8rem) scale(0.8);
    }
  }
}

:defined

定義されているすべての要素を表します。
標準として組み込まれている要素の指定としては、あまり使用することがないかもしれません。
どちらかというとカスタム要素の定義と組み合わせて使うことが多いと思われます。

scss
// JavaScriptでカスタム要素が定義されるまでの間、非表示にする
my-circle:not(:defined) {
  opacity: 0;
  // 縦横を指定することによって、レイアウトシフトを防げる
  width: 100px;
  height: 100px;
}

:host / :host()

Shadow DOMのホストを表します。
ホストは言い換えるとルート要素みたいなもので、Shadow DOMのルート要素を指定できます。
Shadow DOMの内部で指定した場合のみ有効です。
以下の例ではカスタム要素のmy-custom-elementがホストとなります。

html
<my-custom-element></my-custom-element>
scss
// これは外部から指定しているので無視される
:host {
  background-color: green !important;
}
javascript
class MyCustomElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
    this.shadowRoot.innerHTML = `
      <style type="text/css">
        :host {
          display: inline-block;
          padding: 2rem;
        }
        //:hostかつmy-custom-element要素を指定
        :host(my-custom-element) {
          background: #ccc;
        }
        .shadow-dom {
          font-size: 20px;
          font-weight: bold;
        }
      </style>
      <div class="shadow-dom">Shadow DOM</div>
    `;
  }
}
customElements.define("my-custom-element", MyCustomElement);

:scope

セレクターが選択する対象の参照点である要素を表します。
CSSファイルに書いたときは:rootと同じ扱いになるようです。
挙動が変わるのはJavaScriptで要素を取得した時で、取得した要素そのものを:scopeで表せます。
取得済みの要素に対してquerySelector/querySelectorAllなどで子セレクタを使いたいケースなどで便利そうです。

scss
// :rootと同じ扱い。
:scope {
  color: blue;
}
javascript
const container = document.getElementById("container");
// #contaierが:scopeとなる
// :scopeの直下要素を取得したい時に有用
const Nest1Els = container.querySelectorAll(":scope > div");
Nest1Els.forEach((el) => {
  el.style.margin = "20px 0 0";
});

:target

URLのフラグメント(アンカー)に一致するid属性を持つ要素を表します。
#付きのアンカーリンクで、その対象要素にスタイルを当てられます。

html
<a href="#section1">to section1</a>
<section id="section1">
  This is Section 1
</section>
scss
:target {
  color: red;
  background-color: pink;
}

:lang()

ある特定の言語を指定されている要素を表します。
複数言語対応を頻繁にしている方だと、言語ごとにフォントを変更したりする際にそこそこ使うかもしれません。

scss
.text {
  &:lang(ja) {
    color: red;
  }
  &:lang(en) {
    color: blue;
  }
}

:fullscrenn

全画面表示になっている状態を表します。
下記サンプルコードではFullscreen API経由で全画面モード(もしくはその解除)を実行しています。

scss
// 全画面モードでは文字が赤色に。
:fullscreen p {
  color: red;
}
javascript
const req = document.getElementById("requestFull");
const exit = document.getElementById("exitFull");

req.addEventListener("click", () => {
  if (document.fullscreenEnabled) {
    // 全画面モードにする
    document.documentElement.requestFullscreen();
  }
});
exit.addEventListener("click", () => {
  // 全画面モードを解除
  if (document.exitFullscreen) {
    document.exitFullscreen();
  }
});

:first / :left / :right

@pageとともに使われる擬似クラスで、印刷で特定のプロパティ(対象プロパティについてはMDN等を参照してください)を調整できます。
:firstは最初のページ、:leftは左のページ、:rightは右のページを表します。
書字方向が左から右の場合、1ページ目は右(:right)になります。

scss
p {
  page-break-after: always;
}
@page :left {
  // 2つ目のpが対象(buttonも対象)
  margin-left: 0;
}
@page :right {
  // 1つ目と3つ目のpが対象
  // ただし、1つ目のpは:firstで上書きされるので
  // 実際は3つ目のpにだけスタイルが当たる
  margin-left: 50%;
}
@page :first {
  // 1つ目のpが対象
  margin-top: 50%;
  margin-left: 50%;
}
html
<p>最初のページです(:first & :right)</p>
<p>2ページ目(:left)</p>
<p>3ページ目(:right)</p>

まとめ

個人的に使用頻度の低い擬似クラスたちでした。
CSSだけでもできることは増えてきているので、CSSなのかJavaScriptなのか、適切な判断ができるようになりたいですね。
個人としてはまだWeb Componentsを実装する機会がほとんどないのですが、:defined:hostなどはこれから使用する機会か増えていくかもしれません。

参考

https://developer.mozilla.org/ja/docs/Web/CSS/Pseudo-classes

Discussion