Czysty efekt skupienia się na galerii CSS z :not

Węzeł źródłowy: 1723238

W przeszłości często musiałem dowiedzieć się, jak dodać style do wszystkich elementów wewnątrz kontenera, ale nie unosił się jeden.

Demo oczekiwanego efektu „zanikania” u rodzeństwa, aby umożliwić użytkownikom „skupienie się” na konkretnym elemencie.

Efekt ten wymaga wybrania rodzeństwa zawisłego elementu. Kiedyś stosowałem do tego JavaScript, dodając lub usuwając klasę, która zdefiniowała odpowiednie reguły CSS na mouseenter i mouseleave wydarzenia podobne do tego:

Chociaż kod załatwia sprawę, moje przeczucie zawsze podpowiadało mi, że musi istnieć jakiś czysty sposób CSS, aby osiągnąć ten sam wynik. Kilka lat temu, pracując nad pewnym sliderem dla mojej firmy, wpadłem na rozwiązanie podobne do jak Chris Geelhoed odtworzył słynną animację strony głównej Netflix i zrozumiałem, że nie potrzebuję już do tego JavaScript.

Kilka miesięcy temu próbowałem zaimplementować to samo podejście do kanału opartego na siatce na stronie mojej firmy i — boom — to nie zadziałało z powodu luki między elementami!

Na szczęście dla mnie okazało się, że nie musi tak pozostać i po raz kolejny nie potrzebowałem do tego JavaScriptu.

Znaczniki i podstawowy CSS

Zacznijmy kodować od przygotowania odpowiedniego znacznika:

  • .grid jest oparty na siatce

      lista;

    • i .grid__child elementy są
    • dzieci, z którymi chcemy mieć kontakt.

    Znacznik wygląda tak:

    Styl powinien wyglądać tak:

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, 15rem);
      grid-gap: 1rem;
    }
    
    .grid__child {
      background: rgba(0, 0, 0, .1);
      border-radius: .5rem;
      aspect-ratio: 1/1;
    }

    Ten przykładowy kod utworzy trzy elementy listy zajmujące trzy kolumny w siatce.

    Siła selektorów CSS

    Dodajmy teraz trochę interaktywności. Podejście, które początkowo zastosowałem, opierało się na dwóch krokach:

    1. najechanie kursorem na kontener powinno zmienić style wszystkich elementów w środku…  
    2. …oprócz tego, nad którym aktualnie unosi się kursor.

    Zacznijmy od złapania każdego dziecka, gdy kursor znajduje się nad kontenerem:

    .grid:hover .grid__child {
      /* ... */
    }

    Po drugie, wykluczmy aktualnie najechany element i zmniejszmy opacity jakiegokolwiek innego dziecka:

    .grid:hover .grid__child:not(:hover) {
      opacity: 0.3;
    }

    A to byłoby w zupełności wystarczające dla kontenerów bez przerw między elementami potomnymi:

    Animowany plik GIF kursora myszy wchodzącego w interakcję z elementami, które nie są oddzielone żadnymi przerwami.
    Demo rozwiązania, które działa bez luk.

    Jednak w moim przypadku nie udało mi się usunąć tych luk:

    Animowany GIF przedstawiający kursor myszy najeżdżający na elementy. Jednak gdy mysz wejdzie w przerwę między dwoma elementami, efekt kończy się, gdy mysz opuści element.
    Demo problemu napotkanego przy wprowadzaniu luk.

    Kiedy poruszałem myszką pomiędzy kafelkami, wszystkie elementy dzieci znikały.

    Ignorowanie luk

    Możemy założyć, że luki to części kontenera, na które nie nakładają się jego elementy potomne. Nie chcemy uruchamiać efektu za każdym razem, gdy kursor wejdzie do kontenera, ale raczej wtedy, gdy najedzie na jeden z elementów w środku. Czy możemy wtedy zignorować kursor poruszający się nad lukami? 

    Tak, możemy, używając pointer-events: none na .grid pojemnik i przynoszenie ich z powrotem pointer-events: auto na swoich dzieciach:

    .grid {
      /* ... */
      pointer-events: none;
    }
    
    /* ... */
    
    .grid__child {
      /* ... */
      pointer-events: auto;
    }

    Dodajmy tylko fajne przejście na nieprzezroczystość i mamy gotowy komponent:

    Prawdopodobnie jest jeszcze fajniej, gdy dodamy więcej płytek i stworzymy układ dwuwymiarowy:

    Ostateczny CSS wygląda tak:

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, 15rem);
      grid-gap: 3rem;
      pointer-events: none;
    }
    
    .grid:hover .grid__child:not(:hover) {
      opacity: 0.3;
    }
    
    .grid__child {
      background: rgba(0, 0, 0, .1);
      border-radius: .5rem;
      aspect-ratio: 1/1;
      pointer-events: auto;
      transition: opacity 300ms;
    }

    Za pomocą tylko 2 dodatkowych linijek kodu przezwyciężyliśmy problem luki!

    Możliwe problemy

    Chociaż jest to kompaktowe rozwiązanie, istnieją sytuacje, w których może wymagać pewnych obejść.

    Niestety ta sztuczka nie zadziała, gdy chcemy, aby kontener był przewijalny, np. jak w jakimś poziomym suwaku. The pointer-events: none styl zignorowałby nie tylko zdarzenie najechania, ale także wszystkie inne. W takich sytuacjach można owinąć .grid w innym pojemniku, takim jak ten:

    Podsumowanie

    Gorąco zachęcam do eksperymentowania i znalezienia prostszego i bardziej natywnego podejścia do zadań, które zwykle mają pewien poziom złożoności. Technologie internetowe, takie jak CSS, stają się coraz potężniejsze, a korzystając z gotowych natywnych rozwiązań, możesz osiągnąć świetne wyniki bez konieczności utrzymywania kodu i cedowania go na dostawców przeglądarek.

    Mam nadzieję, że spodobał Ci się ten krótki samouczek i okazał się przydatny. Dziękuję!

    Autor wybrał Tech Edukacja otrzymać darowiznę w ramach Napisz na darowizny program.

    Znak czasu:

    Więcej z Sztuczki CSS