scroll-state() w CSS

Podobnie jak zapytania kontenera, ale w przypadku zablokowanych, przyciśniętych i przepełnionych zapytań.

Data publikacji: 15 stycznia 2025 r.

Wersja Chrome 133 rozszerza zapytania dotyczące kontenera o zapytania dotyczące stanu przewijania. Stan zarządzany przez przeglądarkę w przypadku przyklejonego pozycjonowania, punktów przyciągania podczas przewijania i elementów przewijanych można teraz zapytać i dostosować z poziomu CSS.

Omówienie

Przed wykonaniem zapytań dotyczących stanu przewijania musisz użyć kodu JavaScript, aby sprawdzić, czy element jest zablokowany, przytwierdzony czy przewijalny. Teraz istnieje bardziej wydajna metoda śledzenia standardów, która pozwala poznać te informacje i odpowiednio się do nich dostosować. Jest też nowy sposób uruchamiania animacji, który umożliwia odblokowanie animacji uruchamianych przez przewijanie w CSS.

Oto przegląd zapytań stanu dostępnych w Chrome 133:

Stan utknięty:
Zmiana stylu, gdy element jest przyklejony do krawędzi.
Stan spakowany:
Zmiana stylu po przyciągnięciu elementu do osi.
Stan przewijania:
Zmiana stylu, gdy element jest za duży.

Dobra wiadomość jest taka, że wszystko, czego się nauczyłeś/nauczyłaś z zapytań dotyczących kontenera, przyda Ci się w pracy z zapytaniami o stan przewijania.

Niezbadane są też obszary między animacjami wywoływanymi przez przewijanie a zapytaniami do kontenera stanu przewijania. Musimy eksperymentować z czasem i kontekstem, aby ustalić, czy lepiej sprawdzi się animacja wywoływana przez przewijanie czy animacja stanu wywoływana przez przewijanie. Następujący film i prezentacja pokazują, jak wygląda ta sytuacja: porównujemy animację wywoływaną przez przycisk z animacją wywoływaną przez przewijanie.

(po lewej) animacja wywołana przez scroll-state(), (po prawej) animacja wywołana przez przewijanie
https://codepen.io/web-dot-dev/pen/emOrBaV

Pierwsze zapytanie dotyczące stanu przewijania

Pierwszym krokiem jest zdefiniowanie kontenera przy użyciu nowej wartości właściwości container-type. Podobnie jak w przypadku zapytania dotyczącego kontenera, element, którego dotyczy zapytanie, to ten, któremu przypisujesz wartość container-type i opcjonalnie container-name. Za pomocą zapytań o stan przewijania możesz określić, czy element jest przyciągany, zablokowany czy ma przepełnienie container-type: scroll-state.

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;
}

Drugim krokiem jest wybranie elementu podrzędnego tego kontenera, który będzie reagować na stan. W przypadku zapytań dotyczących kontenera nie może to być ten sam element, który ma element container-type.

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  > nav {
    @container scroll-state(stuck: top) {
      background: Highlight;
      color: HighlightText;
    }
  }
}

Trzeci krok to wypróbowanie tej funkcji. W tym przykładzie kodu CSS tło będzie czerwone, gdy element .stuck-top przykleja się do góry w miejscu 0. Dzięki kilku dodatkowym wierszom w CSS, które już napisaliśmy, oraz dodatkowemu elementowi zawierającymu stan przeglądarki nasze komponenty są znacznie bardziej inteligentne w swoim otoczeniu.

https://codepen.io/web-dot-dev/pen/ByBxpwR

Stopniowe ulepszanie

Za pomocą atrybutu @supports i zagnieżdżania możesz dodać funkcje ulepszania stopniowego lub użyć funkcji warunkowych, dodając tylko kilka dodatkowych linii kodu:

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  @supports (container-type: scroll-state) {
    > nav {
      @container scroll-state(stuck: top) {
        background: Highlight;
        color: HighlightText;
      }
    }
  }
}

Jeśli animacja dotyczy elementów na stronie, które są animowane za pomocą zapytań stanu przewijania, pamiętaj też o użyciu @media (prefers-reduced-motion: no-preference) {}.

Przykłady zastosowania

Zablokowane

Może ta sekcja powinna nazywać się „Kłopotliwe sytuacje”? To niewielka kolekcja przypadków użycia przyklejonego stanu oraz dodatkowa sekcja z ideami, które należy wdrożyć.

@container scroll-state(stuck: top) {}
@container scroll-state(stuck: bottom) {}

Pełna lista składni

Dodawanie cienia, gdy element jest zablokowany

Jednym z najczęstszych zastosowań zablokowanego zapytania jest dodanie do zablokowanych pasków nawigacyjnych przycisku box-shadow, który będzie widoczny na nałożonych treściach.

https://codepen.io/web-dot-dev/pen/GgKdryj
.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  > nav {
    transition: box-shadow .3s ease;

    @container scroll-state(stuck: top) {
      box-shadow: var(--shadow-5);
    }
  }
}

Aktywowanie bieżącego nagłówka

Innym typowym scenariuszem jest podświetlenie elementu, który jest obecnie przyklejony. Na liście zespołów uporządkowanych alfabetycznie może to być bardzo przydatne i ułatwiające korzystanie z aplikacji.

https://codepen.io/web-dot-dev/pen/pvzVRaK
.sticky-slide {
  dt {
    container-type: scroll-state;
    position: sticky;
    inset-block-start: 0;
    inset-inline: 0;

    > header {
      transition: 
        background .3s ease,
        box-shadow .5s ease;

      @container scroll-state(stuck: top) {
        background: hsl(265 100% 27%);
        box-shadow: 0 5px 5px #0003;
      }
    }
  }
}

Oto inny wariant, w którym nagłówki znajdują się obok elementów listy. Wiele możliwości

https://codepen.io/web-dot-dev/pen/azoGpGg

Przepełnienie pomysłów

Oto lista demo, które mogą Cię zainspirować do dodania nieco pikanterii do demo lub usunięcia kodu JavaScript za pomocą zapytań stanu przewijania. Proponuję stworzyć taki, który Ci się podoba. Pomoże Ci to zapamiętać składnię i pomysły. 😏

Przyciągnięto

Dzięki zapytaniom o stan przyciętego elementu możemy częściowo zdjąć z kodu JavaScript i zdarzeń Snap odpowiedzialność za obsługę i przekazać ją do kodu CSS.

@container scroll-state(snapped: x) {}
@container scroll-state(snapped: y) {}
@container scroll-state(snapped: inline) {}
@container scroll-state(snapped: block) {}

Pełna lista składni

Przypominamy, że jeśli pominęliście sekcję Pierwsze zapytanie o stan przewijania, kontener zapytania snapa to element z elementem scroll-snap-align, a element, który może się dostosowywać, musi być podrzędnym tego elementu. Oznacza to, że do skonfigurowania tej funkcji potrzebne są 3 elementy:

a scroll container with `scroll-snap-type`
⤷ a snap target with both `scroll-snap-align` and `container-type: scroll-state`
    ⤷ a child of the snap target that can query the container for snap state

wizualnie wzmocnić przycięty element,

W przypadku środka zwisu bardzo często wyróżnia się element, który znajduje się na środku. W tym przykładzie opinii użyto słowa kluczowego not, dzięki czemu wszystkie niesformatowane opinie mają niską przezroczystość, a sformatowana opinia jest w naturalnym stanie.

https://codepen.io/web-dot-dev/pen/NPKMdBX
.demo {
  overflow: auto hidden;
  scroll-snap-type: x mandatory;

  > article {
    container-type: scroll-state;
    scroll-snap-align: center;

    @supports (container-type: scroll-state) {
      > * {
        transition: opacity .5s ease;

        @container not scroll-state(snapped: x) {
          opacity: .25;
        }
      }
    }
  }
}

wyświetlać podpis do przyciętego elementu.

To dobry przykład tego, jak zapytania o stan przewijania umożliwiają animację wywoływaną przez przewijanie. Jest to też dobry przykład sytuacji, w której stosowanie ograniczonego ruchu w CSS jest przydatne.

https://codepen.io/web-dot-dev/pen/XJrqpBG
.demo {
  overflow-x: auto;
  scroll-behavior-x: contain;
  scroll-snap-type: x mandatory;

  > .card {
    container-type: scroll-state;
    scroll-snap-align: center;

    @supports (container-type: scroll-state) {
      @media (prefers-reduced-motion: no-preference) {
        figcaption {
          transform: translateY(100%);

          @container scroll-state(snapped: x) {
            transform: translateY(0);
          }
        }
      }
    }
  }
}

Animowanie elementów slajdu

Podczas wygłaszania prezentacji często stosuje się animacje elementów pokazu slajdów. Wcześniej pisanie obserwatora kolizji było dość uciążliwe, ponieważ robiło tylko tyle, że ustawiało klasę na slajdzie. Teraz nie potrzebujemy kodu JavaScript.

https://codepen.io/web-dot-dev/pen/dPbeNqY
html {
  scroll-snap-type: y mandatory;
}

section {
  container-type: scroll-state;
  scroll-snap-align: start;
  scroll-snap-stop: always;

  @supports (container-type: scroll-state) {
    @media (prefers-reduced-motion: no-preference) {
      > h1 {
        transition: opacity .5s ease, transform .5s var(--ease-spring-3);
        transition-delay: .5s;
        opacity: 0;
        transform: scale(1.25);

        @container scroll-state(snapped: block) {
          opacity: 1;
          transform: scale(1);
        }
      }
    }
  }
}

Możesz zauważyć, że wszystkie zablokowane zapytania o stan usługi porównywania cen działają jak scrollsnapchanging, a nie scrollsnapchange. Dzięki temu możesz wyświetlić wizualne informacje zwrotne dotyczące elementu. Jeśli jest zbyt szybkie, użyj zdarzenia JavaScript.

Przewijanie

Zapytanie o stan przewijania będzie bardzo przydatne do wyświetlania wizualnych możliwości, gdy obszar przewijania jest rzeczywiście przewijany. Do czasu pojawienia się zapytań o stan przewijania trudno było poznać te informacje.

@container scroll-state(scrollable: top) {}
@container scroll-state(scrollable: right) {}
@container scroll-state(scrollable: bottom) {}
@container scroll-state(scrollable: left) {}

Pełna lista składni

Wskazanie przewijania za pomocą cieni

Istnieje znany trik CSS Lea Verou, który wykorzystuje background-attachment: local do uzyskania podobnego efektu, a także sposób na wykonanie tego za pomocą animacji sterowanej przez przewijanie. Każda technika ma swoje wady i zalety. Musimy więc sprawdzić, kiedy i gdzie dana technika jest najbardziej odpowiednia.

W tym przykładzie użyto jednego elementu przyklejonego, który zajmuje całą szerokość ekranu. Gradient u góry i gradient u dołu mają przezroczystość animowaną za pomocą @property, gdy ma zastosowanie zapytanie o kontekstowy stan przewijania: @container scroll-state(scrollable: top).

Zauważ też, że jest to pierwszy kontener, który jest jednocześnie kontenerem size i scroll-state.

https://codepen.io/web-dot-dev/pen/OPLZWBj
.scroll-container {
  container-type: scroll-state size;
  overflow: auto;

  &::after {
    content: " ";

    background: var(--_shadow-top), var(--_shadow-bottom);
    transition: 
      --_scroll-shadow-color-1-opacity .5s ease,
      --_scroll-shadow-color-2-opacity .5s ease;

    @container scroll-state(scrollable: top) {
      --_scroll-shadow-color-1-opacity: var(--_shadow-color-opacity, 25%);
    }

    @container scroll-state(scrollable: bottom) {
      --_scroll-shadow-color-2-opacity: var(--_shadow-color-opacity, 25%);
    }
  }
}

Prompt z strzałką

Czasami wyświetlenie strzałki może pomóc użytkownikom odkryć, że dany obszar można przewijać. Zwykle wskazują one kierunek, w jakim można przewijać, i znikają, gdy nie są już potrzebne. Możesz to zrobić za pomocą tego kodu.

https://codepen.io/web-dot-dev/pen/OPLZWBj
@container scroll-state((scrollable: top) or (not (scrollable: bottom))) {
  translate: 0 calc(100% + 10px);
}

@container scroll-state((scrollable: top) and (not (scrollable: bottom))) {
  translate: 0 calc(100% + 10px);
  rotate: .5turn;
}

Wróć do góry strony

Inną popularną interakcją w stanie przewijania jest przycisk „przewiń do góry”. Poniższy kod powoduje, że przycisk przewijania do góry znika, gdy nie ma możliwości przewijania w górę.

To rozwiązanie jest nieco odwrócone, ale pozwala zmniejszyć ilość kodu CSS. Przycisk jest widoczny, więc musisz go ukryć, gdy nie można już przewijać w górę.

https://codepen.io/web-dot-dev/pen/OPLZWBj
@container not scroll-state(scrollable: top) {
  translate: 0 calc(100% + 10px);
}

dalsze badania;

Jeśli chcesz dowiedzieć się więcej, zapoznaj się z tymi materiałami, w których znajdziesz informacje o specyfikacji oraz inne przydatne artykuły na ten temat: