:has() の事例紹介

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

CSS には、子に基づいて親要素を直接選択する方法がないことが知られています。これは、長年にわたりデベロッパーの皆様から最も多くのご要望をいただいていたものです。この問題は、:has() セレクタによって解決され、現在はすべての主要なブラウザでサポートされています。:has() 以前は、長いセレクタをチェーンしたり、フックのスタイルを設定したりするためにクラスを追加していました。要素とその子孫の関係に基づいてスタイルを設定できるようになりました。:has() セレクタの詳細については、CSS Wrapped 2023すべてのフロントエンド デベロッパーが知っておくべき 5 つの CSS スニペットをご覧ください。

このセレクタは小規模に見えますが、非常に多くのユースケースを実現できます。この記事では、e コマース企業が :has() セレクタによって実現したユースケースを紹介します。

:has() は、Baseline Newly Available の一部です。

対応ブラウザ

  • 105
  • 105
  • 121
  • 15.4

ソース

e コマース企業が新しい CSS と UI 機能を使用してウェブサイトをどのように改善したかについて説明している、この記事が含まれているシリーズ全体をご覧ください。

ポリシーバザール

:has() セレクタにより、ユーザーの選択を JavaScript ベースで検証する必要がなくなり、以前と同じエクスペリエンスでシームレスに動作する CSS ソリューションに置き換えることができました。- Policybazaar テクニカル リーダー Aman Soni

Policybazaar の Investment チームは、:has() セレクタを巧みに応用して、プランを比較しているユーザーに視覚的にわかりやすく表示しています。次の画像は、比較 UI 内に 2 種類のプラン(黄色と青)を示しています。各プランは独自のタイプのみと比較できます。:has() を使用すると、ユーザーが一方のプランを選択した場合、もう一方のプランは選択できなくなります。

:has() を実装して親要素とその子のスタイルを設定し、カテゴリ限定の選択機能を作成します。

コード

:has() を使用すると、親要素とその子のスタイルを設定できます。次のコードは、親コンテナに .disabled-group クラスが設定されているかどうかを確認します。含まれている場合、カードはグレー表示され、pointer-eventsnone に設定することで [追加] ボタンがクリックに反応しなくなります。

.plan-group-container:has(.disabled-group) {
  opacity: 0.5;
  filter: grayscale(100%);
}

.plan-group-container:has(.disabled-section) .button {
  pointer-events: none;
  border-color: #B5B5B5;
  color: var(--text-primary-38-color);
  background: var(--input-border-color);
}

Policybazaar のヘルスチームは、若干異なるユースケースを実装しました。ユーザー用のインライン テストを用意し、:has() を使用して質問のチェックボックスのステータスをチェックし、質問が回答済みかどうかを確認します。オンの場合、アニメーションが適用されて次の質問に移ります。

health.policybazaar.com/

コード

プランの比較の例では、:has() を使用してクラスの存在を確認しています。:has(input:checked) を使用して、チェックボックスなどの入力要素の状態を確認することもできます。クイズを示すビジュアルでは、紫色のバナーの各質問がチェックボックスになっています。Policybazaar は :has(input:checked) を使用して質問の回答が回答済みかどうかを確認し、回答済みの場合は animation: quesSlideOut 0.3s 0.3s linear forwards を使用してアニメーションをトリガーし、次の質問にスライドします。次のコードで、その仕組みを確認します。

.segment_banner__wrap__questions {
 position: relative;
 animation: quesSlideIn 0.3s linear forwards;
}

.segment_banner__wrap__questions:has(input:checked) {
 animation: quesSlideOut 0.3s 0.3s linear forwards;
}


@keyframes quesSlideIn {
 from {
   transform: translateX(50px);
   opacity: 0;
 }
 to {
   transform: translateX(0px);
   opacity: 1;
 }
}

@keyframes quesSlideOut {
 from {
   transform: translateX(0px);
   opacity: 1;
 }
 to {
   transform: translateX(-50px);
   opacity: 0;
 }
}

Tokopedia

Tokopedia は、商品のサムネイルに動画が含まれている場合、:has() を使用してオーバーレイ画像を作成しました。商品サムネイルに .playIcon クラスが含まれている場合は、CSS オーバーレイが追加されます。ここでは、すべてのサムネイルに適用される包括的な .thumbnailWrapper クラス内で、:has() セレクタを & ネスト セレクタとともに使用しています。これにより、CSS のモジュール性が高まり、読みやすくなります。

has セレクタの使用前と使用後の Tokopedia ページのスクリーンショット。
:has() を使用する前と後

コード

次のコードでは、CSS セレクタとコンビネータ&>)を使用し、:has() でネストしてサムネイルのスタイルを設定しています。対応していないブラウザに対しては、通常の追加 CSS クラスルールがフォールバックとして使用されます。@supports selector(:has(*)) ルールは、ブラウザのサポートの確認にも使用されます。したがって、全体的なエクスペリエンスはブラウザのバージョン間で同じです。

export const thumbnailWrapper = css`
  padding: 0;
  margin-right: 7px;
  border: none;
  outline: none;
  background: transparent;

  > div {
    width: 64px;
    height: 64px;
    overflow: hidden;
    cursor: pointer;
    border-color: ;
    position: relative;
    border: 2px solid ${NN0};
    border-radius: 8px;
    transition: border-color 0.25s;

    &.active {
      border-color: ${GN500};
    }

    @supports selector(:has(*)) {
      &:has(.playIcon) {
        &::after {
          content: '';
          display: block;
          background: rgba(0, 0, 0, 0.2);
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
        }
      }
    }

    & > .playIcon {
      position: absolute;
      top: 25%;
      left: 25%;
      width: 50%;
      height: 50%;
      text-align: center;
      z-index: 1;
    }
  }
`;

:has() を使用する際の考慮事項

:has() を他のセレクタと組み合わせて、より複雑な条件を作成します。ファミリー セレクタの has() で例をご確認ください。

リソース:

スクロールドリブン アニメーション、ビュー遷移、ポップオーバー、コンテナクエリなど、新しい CSS や UI 機能を使用することで e コマース企業にメリットがもたらされた他の記事もご覧ください。