:has() – studia przypadków

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

W CSS nie było do tej pory możliwości bezpośredniego wybrania elementu nadrzędnego na podstawie jego elementów podrzędnych. Deweloperzy od wielu lat prosili o to. Rozwiązaniem jest selektor :has(), który jest teraz obsługiwany przez wszystkie główne przeglądarki. Przed :has() często łańcuchowało się długie selektory lub dodawało klasy do stylizacji. Teraz możesz nadawać styl na podstawie relacji elementu z jego potomkami. Więcej informacji o selektorze :has() znajdziesz w artykule Opakowanie CSS 2023 i 5 fragmentów kodu CSS, które każdy programista frontendu powinien znać.

Chociaż ten selektor wydaje się niewielki, może umożliwić ogromną liczbę zastosowań. W tym artykule przedstawiamy kilka zastosowań, które firmy e-commerce mogą wykorzystać dzięki selektorowi :has().

:has() jest częścią punktu odniesienia ponownie dostępnego.

Obsługa przeglądarek

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

Źródło

Obejrzyj całą serię, do której należy ten artykuł, i dowiedz się, jak firmy e-commerce ulepszyły swoje strony dzięki nowym funkcjom CSS i interfejsu.

Policybazaar

Dzięki selektorowi :has() udało nam się wyeliminować walidację wyboru użytkownika opartą na JavaScriptzie i zastąpić ją rozwiązaniem opartym na arkuszu CSS, które działa bez zarzutu i w taki sam sposób jak wcześniej.—Aman Soni, Tech Lead, Policybazaar

Zespół ds. inwestycji w Policybazaar wykorzystał selektor :has(), aby zapewnić użytkownikom wyraźne wizualne wskazanie porównywanych planów. Na poniższym obrazie widać 2 typy planów w interfejsie porównywania (żółty i niebieski). Każdy abonament można porównać tylko z własnym typem. Gdy użytkownik wybierze jeden typ planu, nie będzie mógł wybrać innego typu planu.:has()

Wdroż :has(), aby nadać styl elementowi nadrzędnemu i jego elementom podrzędnym i utworzyć funkcję wyboru powiązaną z kategorią.

Kod

:has() zapewnia dostęp do stylów elementów nadrzędnych i ich elementów podrzędnych. Poniższy kod sprawdza, czy kontener nadrzędny ma ustawioną klasę .disabled-group. Jeśli tak się stanie, karta zostanie wyszarzona, a przycisk „Dodaj” nie będzie reagować na kliknięcia. Aby tego uniknąć, ustaw wartość pointer-events na none.

.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);
}

Zespół Health Policybazaar wdrożył nieco inny przypadek użycia. Użytkownik ma quiz wbudowany w treści, a Ty możesz użyć pola wyboru :has(), aby sprawdzić, czy pytanie zostało już przez niego rozwiązane. Jeśli tak, animacja przeniesie Cię do następnego pytania.

health.policybazaar.com/

Kod

W przykładzie porównania abonamentów użyto :has() do sprawdzenia obecności klasy. Za pomocą :has(input:checked) możesz też sprawdzić stan elementu wejściowego, np. pola wyboru. W wizualizacji pokazującej quiz każde pytanie na fioletowym banerze jest oznaczone polem wyboru. Policybazaar sprawdza, czy pytanie zostało już answered za pomocą :has(input:checked). Jeśli tak, uruchamia animację za pomocą animation: quesSlideOut 0.3s 0.3s linear forwards, aby przejść do następnego pytania. Więcej informacji na ten temat znajdziesz w kodzie poniżej.

.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 używa :has() do tworzenia obrazu nakładki, jeśli miniatura produktu zawiera film. Jeśli miniatura produktu zawiera klasę .playIcon, dodana jest nakładka CSS. W tym przykładzie selektor :has() jest używany razem z selektorem zagnieżdżonym & w ramach ogólnej klasy .thumbnailWrapper, która ma zastosowanie do wszystkich miniatur. Dzięki temu kod CSS jest bardziej modułowy i czytelny.

Zrzut ekranu strony Tokopedia przed i po użyciu selektora „zawiera”.
Przed i po użyciu narzędzia :has().

Kod

Ten kod używa selektorów i kombinatorów arkusza CSS (&>) oraz zagnieżdżania za pomocą :has(), aby nadać miniaturze odpowiedni styl. W przypadku nieobsługiwanych przeglądarek jako kreacji zastępczej używana jest standardowa reguła dodatkowych klas CSS. Reguła @supports selector(:has(*)) służy też do sprawdzania obsługi przeglądarek. Dzięki temu wszystkie wersje przeglądarki działają tak samo.

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;
    }
  }
`;

Co należy wziąć pod uwagę podczas korzystania z :has()

Aby utworzyć bardziej złożony warunek, połącz :has() z innymi elementami selektora. Zapoznaj się z przykładami funkcji has() w selektorze rodziny.

Zasoby:

Przeczytaj inne artykuły z tej serii, aby dowiedzieć się, jak firmy e-commerce korzystały z nowych funkcji CSS i interfejsu, takich jak animacje sterowane przewijaniem, przejścia między widokami, popovery i zapytania kontenerowe.