:has() の事例紹介

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

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

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

:has()ベースラインの新規リリースの一部です。

対応ブラウザ

  • Chrome: 105。
  • Edge: 105。
  • Firefox: 121。
  • Safari: 15.4。

ソース

この記事は、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 オーバーレイが追加されます。ここでは、すべてのサムネイルに適用される包括的な .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 コマース企業がどのようにメリットを得たかについて、このシリーズの他の記事をご覧ください。