BLOG

擬似クラス :has() を使ったフォームのスタイリング

Written by koizumi

INDEX

:has()擬似クラスは特定の条件を満たす子孫要素を持つ親要素を選択するために使用されます。

:has()を使うことによって、従来のCSSだけでは難しかった「特定の子孫要素がある親要素をスタイリングする」ことが可能になりました。

2023年12月にfirefoxでサポートされたことにより、現在は全てのモダンブラウザで使えるようになっています。

今回はお問い合わせフォームでよく見かける5つの要素を:has()擬似クラスを使ってスタイリングする方法をご紹介いたします。

:has()の使い方についてはこちらの記事も参照してください。

1. 必須項目のラベルにマーカーをつける

名前やメールアドレスといった入力が必須の項目について、必須であることを示すためにラベルテキストの隣にマーカーをつけることがあります。

子要素に input:required を持つdivの子要素 labelを指定することでラベルテキストの隣にマーカーをつけることができます。

html

<form>
  <div>
    <label for="name">名前</label>
    <input type="text" name="name" id="name" placeholder="例) 山田太郎" required>
  </div>
</form>

css

div:has(input:required) > label::after {
  content: "必須";
  margin-left: 8px;
  font-size: 10px;
  background-color: #eeeeee;
  color: red;
  padding: 2px 3px;
  border-radius: 2px;
}

サンプル

inputlabelの内側にある場合も、子要素にinput:requiredを持つlabelの子要素(下記の例ではspan)を指定することで適用できます。

HTML

<form>
  <div>
    <label for="name">
      <span>名前</span>
      <input type="text" name="name" id="name" placeholder="例) 山田太郎" required>
     </label>
  </div>
</form>

css

label:has(input:required) > span::after {
  content: "必須";
  margin-left: 8px;
  font-size: 10px;
  background-color: #eeeeee;
  color: red;
  padding: 2px 3px;
  border-radius: 2px;
}

サンプル

2. 入力形式が正しくない場合にメッセージを表示する

メールアドレスを入力するinput欄に〇〇〇@〇〇〇といったメールアドレス形式以外で文字を入力した場合にエラーメッセージを出せるようにします。

以下の例ではinput内の入力要素が無効、かつフォーカスされていない場合に、エラーメッセージを表示します。

HTML

<form>
  <div class="form-item">
    <label for="email">メールアドレス</label>
    <input type="email" id="email" name="email" placeholder="例) [email protected]" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$">
    <div class="form-item__error">有効なメールアドレスを入力してください</div>
    </div>
  </div>
</form>

css

/* 入力が正しくない時にメッセージ表示 */
.form-item:has(input:invalid:not(:placeholder-shown)) > .form-item__error {
    display: block; 
}

/* フォーカス中はメッセージを非表示 */
.form-item:has(input:focus:invalid:not(:placeholder-shown)) >.form-item__error {
    display: none; 
}

サンプル

3. チェックボックスがチェックされている時にラベルのスタイルを変える

チェックの有無をわかりやすくするために、チェックボックスでチェックされている項目のみスタイルを変えることができます。

子要素に:checked擬似クラスを持つdivの子要素label を指定することで、チェックされたラベルにスタイルを適用できます。

HTML

<form>
  <div class="header">当社を知ったきっかけ</div>
  <div class="check-list">
    <div class="check-item">
      <input type="checkbox" id="search" name="search"/>
      <label for="search">インターネット検索</label>
     </div>
     <div class="check-item">
      <input type="checkbox" id="ad" name="ad"/>
      <label for="ad">WEB広告</label>
    </div>
    <div class="check-item">
      <input type="checkbox" id="sns" name="sns"/>
      <label for="sns">SNS</label>
    </div>
    <div class="check-item">
      <input type="checkbox" id="other" name="other"/>
      <label for="other">その他</label>
    </div>
  </div>
</form>

css

.check-item:has(:checked) label {
  background-color: #DEFFFD;
  font-weight: 700;
}

サンプル

4. 選択によって解答欄を追加で表示する

セレクトメニューで「その他」を選択した時などに解答欄を追加で表示することができます。

:has()疑似クラスを使用し、セレクトメニューで「その他」が選択されているかどうかをチェックし、それに基づいて新たな解答欄を表示します。

HTML

<form>
  <label for="occupation-select">職種</label>
  <select name="occupation" id="occupation-select">
    <option value=""></option>
    <option value="director">ディレクター</option>
    <option value="designer">デザイナー</option>
    <option value="engineer">エンジニア</option>
    <option value="other">その他</option>
  </select>
  <div class="other-field">
    <label for="other-occupation">「その他」を選んだ方は職種をご入力ください。</label>
    <input type="text" name="other-occupation" id="other-occupation" placeholder="例) 広報">
  </div>
</form>

css

form:has(option[value="other"]:checked) .other-field {
  display: block;
}

.other-field {
  margin-top: 20px;
  display: none;
}

サンプル

5. 同意チェックボタンを実装する

フォームによっては利用規約などの同意チェックボックスにチェックを入れたときのみフォーム内容を送信できるようにしたい場合があります。

form内にチェックの入ったinput要素があるかを判別して、input[type=submit]ボタン要素に対して活性/非活性を切り替えることができます。

HTML

<form>
    <label>
      <input class="checkbox" type="checkbox"/>
      個人情報の取り扱いに同意する
    </label>
    <input class="button" type="submit" value="送信する"></b>
</form>

css

cssではinput系のクリック動作等を無効にするdisabled属性の操作はできないので、
pointer-events: none;でクリックおよびタップ動作を無効化しています。

また、pointer-events: none;のみだと、キーボード操作等でボタンにフォーカスした状態だと押下することができてしまうので、非活性時にフォーカスした際にはvisibility: hidden;でフォーカス状態を外し、活性時には有効になるようにしています。

/* 同意にチェックがある場合に送信ボタンを活性化 */
form:has(input:checked) input[type=submit] {
  border: #000 solid 1px;
  color: #333;
  cursor: pointer;
  pointer-events: auto;
  /* 活性時はフォーカス状態を有効にする */
  &:focus {
    visibility: visible;
  }
  /* 活性時のホバー */
  &:hover {
    background: #000;
    color: #fff;
  }
}

/* 送信ボタン デフォルトで非活性 */
input[type=submit] {
  display: block;
  margin: 20px auto 0;
  background-color: #efefef;
  border: #aaa solid 1px;
  border-radius: 10px;
  color: #aaa;
  padding: 10px 80px;
  pointer-events: none;
  transition: background-color .3s, color .5s;
  /* 非活性時はフォーカス状態を外す */
  &:focus {
    visibility: hidden;
  }
}

サンプル

まとめ

いかがでしたか?

:has()擬似クラスを利用することによって、お問い合わせフォームでよく見かける要素をcssのみで手軽に実装することができます。

フォームを実装する際は是非参考にしてください!

参考

:has() - CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/:has

CSSの:has()疑似クラスの便利な使い方を徹底解説
https://coliss.com/articles/build-websites/operation/css/has-pseudo-class.html

具体例で :has() の活用をイメージする
https://zenn.dev/yy616/articles/188e0761277fdf

新しい擬似クラス:has()⁠⁠、:is()⁠⁠、:where()を使いこなそう
https://gihyo.jp/article/2024/10/ride-modern-frontend-01

:has() 擬似クラスを使って CSS だけで必須フィールドのラベルに * マーカーを付ける
https://qiita.com/aster-mnch/items/9c646a95de08ddef7a12

:has()を使ってCSSだけで同意チェックボタンを実装する方法
https://black-flag.net/css/20240717-8157.html