:has() の事例紹介

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

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

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

この記事が属するシリーズ全体では、e コマース企業が新しい CSS 機能と UI 機能を使用してウェブサイトを強化した方法について説明しています。

Policybazaar

:has() セレクタを使用することで、ユーザーの選択の JavaScript ベースの検証 を排除し、CSS ソリューションに置き換えることができました。これにより、以前と同じエクスペリエンスで シームレスに動作しています。 - Aman Soni、Tech Lead、Policybazaar

Policybazaar の投資チームは、:has() セレクタを巧みに適用して、プランを比較しているユーザーにわかりやすい視覚的な表示を提供しています。次の画像は、比較 UI 内の 2 種類のプラン(黄色と青)を示しています。各プランは、同じタイプのプランとのみ比較できます。:has() を使用すると、ユーザーが 1 つのタイプのプランを選択すると、別のプランタイプを選択できなくなります。

: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 オーバーレイが追加されます。ここでは、` :has()` セレクタは、すべてのサムネイルに適用される包括的な .thumbnailWrapper クラス内の & ネスト セレクタとともに使用されます。これにより、よりモジュール化され、読みやすい 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() ファミリー セレクタの例をご覧ください。

リソース:

このシリーズの他の記事では、e コマース企業がスクロール駆動型アニメーション、ビュー遷移、ポップオーバー、コンテナクエリなどの新しい CSS 機能と UI 機能を使用してどのようにメリットを得たかについて説明しています。