CSS-состояние прокрутки(), CSS-состояние прокрутки()

Как контейнерные запросы; но для застрявших, зависших и переполненных запросов.

Опубликовано: 15 января 2025 г.

Chrome 133 основывается на запросах контейнеров, вводя запросы контейнеров с состоянием прокрутки. Управляемое браузером состояние для закрепленного позиционирования, точек привязки прокрутки и прокручиваемых элементов теперь можно запрашивать и адаптировать из CSS.

Обзор

Прежде чем запрашивать состояние прокрутки, вам нужно будет использовать JavaScript, чтобы понять, застрял ли элемент, защелкнулся или прокручивается. Теперь на пути стандартов появился более эффективный метод получения этой информации и соответствующей адаптации. Также появился новый способ запуска анимации, разблокирующий анимацию, запускаемую прокруткой, из CSS.

Вот обзор запросов состояния, доступных в Chrome 133:

Состояние зависания :
Стиль триггера меняется, когда элемент прилипает к краю.
Зафиксированное состояние :
Стиль триггера меняется, когда элемент привязывается к оси.
Прокручиваемое состояние :
Стиль триггера меняется, когда элемент переполнен.

Хорошая новость заключается в том, что все, что вы узнали из запросов к контейнерам, поможет вам работать с запросами состояния прокрутки.

Существует также неизведанная территория между анимацией, управляемой прокруткой , и запросами контейнера состояния прокрутки; нам нужно поэкспериментировать со временем и контекстом, чтобы определить, какая анимация, управляемая прокруткой, или анимация состояния прокрутки, запускаемая прокруткой, будет лучше. Следующее видео и демонстрация иллюстрируют затруднительное положение; липкая триггерная анимация по сравнению с анимацией, управляемой прокруткой.

(слева) анимация, запускаемая Scroll-state(), (справа) анимация, управляемая прокруткой
https://codepen.io/web-dot-dev/pen/emOrBaV

Первый запрос состояния прокрутки

Первым шагом является определение контейнера, используя новое значение свойства container-type . Как и в случае с запросом контейнера, элемент, который вы хотите запросить, — это тот элемент, которому вы указываете container-type и, при необходимости, container-name . С помощью запросов состояния прокрутки вы указываете элемент, который привязывается, застревает или имеет container-type: scroll-state .

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

Второй шаг — выбрать дочерний элемент этого контейнера, который будет реагировать на состояние, поскольку в запросах контейнера это не может быть тот же элемент, который имеет container-type .

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

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

Третий шаг — попробовать. В следующем примере CSS фон будет оформлен в красный цвет, когда элемент .stuck-top прикрепится к верхнему значению 0 . Благодаря нескольким дополнительным строкам в CSS, которые мы уже написали, и дополнительному содержащему элементу, который передает состояние браузера, наши компоненты гораздо умнее относятся к своему окружению.

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

Прогрессивное улучшение

Правило @supports и вложенность позволяют добавлять прогрессивное улучшение или условное использование функций всего за пару дополнительных строк кода:

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

Кроме того, не забудьте использовать @media (prefers-reduced-motion: no-preference) {} для вашего движения, если в конечном итоге вам придется анимировать элементы на странице с помощью запросов состояния прокрутки.

Варианты использования

Застрявший

Возможно, этот раздел следует назвать «Неприятные ситуации»? Это небольшая коллекция сценариев использования закрепленных состояний, а также бонусный раздел идей, которые необходимо реализовать.

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

Полный список синтаксиса

Добавить тень при застревании

Один из наиболее распространенных случаев использования зависшего запроса — это панели навигации, которые хотят добавить box-shadow при зависании, чтобы они могли казаться плавающими над содержимым, которое они накладывают.

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

Активировать текущий застрявший заголовок

Другой распространенный сценарий закрепления обратной связи пользовательского интерфейса — выделение застрявшего в данный момент элемента. В списке групп, расположенных в алфавитном порядке, это может быть очень полезно и полезно для опыта.

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

Вот еще один вариант, в котором заголовки находятся сбоку от элементов списка. Много возможностей!

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

Переполнение идей

Вот список запоминающихся демонстраций, которые могут вдохновить вас добавить в демо немного остроты или удалить JavaScript с помощью запросов состояния прокрутки. Я предлагаю попробовать создать тот, который вам понравится, это поможет сохранить синтаксис и идеи 😏.

Защелкнуто

С помощью запросов привязанного состояния мы можем снять часть ответственности с JavaScript и Snap Events и перенести обработку на CSS.

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

Полный список синтаксиса

Небольшое напоминание: если вы пропустили раздел «Первый запрос состояния прокрутки» , контейнером для запроса привязки является элемент с scroll-snap-align , а элемент, который может адаптироваться, должен быть дочерним элементом этого элемента. Это означает, что для настройки необходимы три элемента:

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

Визуально увеличить привязанный элемент

С помощью скроллера с центральной привязкой очень часто можно выделить или выделить элемент, привязанный к центру. В этом примере отзывов используется ключевое слово not , поэтому все несвязанные отзывы имеют низкую непрозрачность, в то время как закрепленные отзывы остаются в своем естественном состоянии представления.

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

Показать заголовок прикрепленного элемента

Это хороший пример того, как запросы состояния прокрутки включают анимацию, запускаемую прокруткой. Это также хороший пример того, как в CSS важно соблюдать ограничение движения.

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

Анимация в элементах слайда

Во время выступления очень часто анимируют элементы слайд-шоу или презентации. Раньше было довольно неприятно писать для этого обозреватель пересечений, который всего лишь устанавливал класс на слайде. Теперь нам не нужен никакой 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);
        }
      }
    }
  }
}

Вы могли заметить, что все привязанные запросы состояния CSS ведут себя как scrollsnapchanging , а не как scrollsnapchange . Это дает вам самый ранний крючок для обеспечения визуальной обратной связи привязываемого элемента. Если он слишком нетерпелив, рассмотрите событие JavaScript.

Прокручиваемый

Запрос состояния прокрутки будет очень полезен для демонстрации визуальных возможностей того, когда область прокрутки действительно можно прокручивать. До получения запросов о состоянии прокрутки эту информацию было сложно узнать .

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

Полный список синтаксиса

Обозначить прокрутку тенями

Леа Веру использует знаменитый CSS-трюк , который использует background-attachment: local для достижения эффекта, подобного этому, а также способ сделать это с помощью анимации, управляемой прокруткой . У каждого метода есть свои компромиссы, и нам предстоит выяснить, когда и где каждый из этих методов подходит лучше всего.

В следующем примере используется один липкий элемент, охватывающий область прокрутки. Непрозрачность градиента вверху и градиента внизу анимируется с помощью @property когда применяется контекстный запрос состояния прокрутки: @container scroll-state(scrollable: top) .

Также обратите внимание, что это первый контейнер, который одновременно является контейнером size и 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%);
    }
  }
}

Подсказка со стрелкой

Иногда отображение стрелки может помочь пользователям обнаружить, что область можно прокручивать. Они, как правило, указывают направление, в котором может происходить прокрутка, и исчезают, когда они больше не нужны. Вы можете сделать это с помощью следующего кода.

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

Вернуться наверх

Еще одно популярное взаимодействие с состоянием прокрутки — это удобная кнопка «прокрутить вверх». Следующий код приводит к исчезновению кнопки прокрутки вверх, когда прокручивать вверх некуда.

Это решение немного перевернуто, но позволяет уменьшить количество CSS. Естественное место расположения кнопки видно, поэтому вам нужно указать ей, чтобы она скрывалась, когда больше некуда прокручивать вверх.

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

Продолжение исследования

Если вы ищете больше, вот несколько ресурсов, которые варьируются от подробностей спецификаций до других замечательных статей по этой теме:

,

Как контейнерные запросы; но для застрявших, зависших и переполненных запросов.

Опубликовано: 15 января 2025 г.

Chrome 133 основывается на запросах контейнеров, вводя запросы контейнеров с состоянием прокрутки. Управляемое браузером состояние для закрепленного позиционирования, точек привязки прокрутки и прокручиваемых элементов теперь можно запрашивать и адаптировать из CSS.

Обзор

Перед запросами состояния прокрутки вам нужно будет использовать JavaScript, чтобы понять, застрял ли элемент, защелкнулся или прокручивается. Теперь на пути стандартов появился более эффективный метод получения этой информации и соответствующей адаптации. Также появился новый способ запуска анимации, разблокирующий анимацию, запускаемую прокруткой, из CSS.

Вот обзор запросов состояния, доступных в Chrome 133:

Состояние зависания :
Стиль триггера меняется, когда элемент прилипает к краю.
Зафиксированное состояние :
Стиль триггера меняется, когда элемент привязывается к оси.
Прокручиваемое состояние :
Стиль триггера меняется, когда элемент переполнен.

Хорошая новость заключается в том, что все, что вы узнали из запросов к контейнерам, поможет вам работать с запросами состояния прокрутки.

Существует также неизведанная территория между анимацией, управляемой прокруткой , и запросами контейнера состояния прокрутки; нам нужно поэкспериментировать со временем и контекстом, чтобы определить, какая анимация, управляемая прокруткой, или анимация состояния прокрутки, запускаемая прокруткой, будет лучше. Следующее видео и демонстрация иллюстрируют затруднительное положение; липкая триггерная анимация по сравнению с анимацией, управляемой прокруткой.

(слева) анимация, запускаемая Scroll-state(), (справа) анимация, управляемая прокруткой
https://codepen.io/web-dot-dev/pen/emOrBaV

Первый запрос состояния прокрутки

Первым шагом является определение контейнера, используя новое значение свойства container-type . Как и в случае с запросом контейнера, элемент, который вы хотите запросить, — это тот элемент, которому вы указываете container-type и, при необходимости, container-name . С помощью запросов состояния прокрутки вы указываете элемент, который привязывается, застревает или имеет container-type: scroll-state .

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

Второй шаг — выбрать дочерний элемент этого контейнера, который будет реагировать на состояние, поскольку в запросах контейнера это не может быть тот же элемент, который имеет container-type .

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

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

Третий шаг — попробовать. В следующем примере CSS фон будет оформлен в красный цвет, когда элемент .stuck-top прикрепится к верхнему значению 0 . Благодаря нескольким дополнительным строкам в CSS, которые мы уже написали, и дополнительному содержащему элементу, который передает состояние браузера, наши компоненты гораздо умнее относятся к своему окружению.

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

Прогрессивное улучшение

Правило @supports и вложенность позволяют добавлять прогрессивное улучшение или условное использование функций всего за пару дополнительных строк кода:

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

Кроме того, не забудьте использовать @media (prefers-reduced-motion: no-preference) {} для вашего движения, если в конечном итоге вам придется анимировать элементы на странице с помощью запросов состояния прокрутки.

Варианты использования

Застрявший

Возможно, этот раздел следует назвать «Неприятные ситуации»? Это небольшая коллекция сценариев использования закрепленных состояний, а также бонусный раздел идей, которые необходимо реализовать.

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

Полный список синтаксиса

Добавить тень при застревании

Один из наиболее распространенных случаев использования зависшего запроса — это панели навигации, которые хотят добавить box-shadow при зависании, чтобы они могли казаться плавающими над содержимым, которое они накладывают.

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

Активировать текущий застрявший заголовок

Другой распространенный сценарий закрепления обратной связи пользовательского интерфейса — выделение застрявшего в данный момент элемента. В списке групп, расположенных в алфавитном порядке, это может быть очень полезно и полезно для опыта.

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

Вот еще один вариант, в котором заголовки находятся сбоку от элементов списка. Множество возможностей!

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

Переполнение идей

Вот список запоминающихся демонстраций, которые могут вдохновить вас добавить в демо немного остроты или удалить JavaScript с помощью запросов состояния прокрутки. Я предлагаю попробовать создать тот, который вам понравится, это поможет сохранить синтаксис и идеи 😏.

Защелкнуто

С помощью запросов привязанного состояния мы можем снять часть ответственности с JavaScript и Snap Events и перенести обработку на CSS.

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

Полный список синтаксиса

Небольшое напоминание: если вы пропустили раздел «Первый запрос состояния прокрутки» , контейнером для запроса привязки является элемент с scroll-snap-align , а элемент, который может адаптироваться, должен быть дочерним элементом этого элемента. Это означает, что для настройки необходимы три элемента:

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

Визуально увеличить привязанный элемент

С помощью скроллера с центральной привязкой очень часто можно выделить или выделить элемент, привязанный к центру. В этом примере отзывов используется ключевое слово not , поэтому все несвязанные отзывы имеют низкую непрозрачность, в то время как закрепленные отзывы остаются в своем естественном состоянии представления.

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

Показать заголовок прикрепленного элемента

Это хороший пример того, как запросы состояния прокрутки включают анимацию, запускаемую прокруткой. Это также хороший пример того, как в CSS важно соблюдать ограничение движения.

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

Анимация в элементах слайда

Во время выступления очень часто анимируют элементы слайд-шоу или презентации. Раньше было довольно неприятно писать для этого обозреватель пересечений, который всего лишь устанавливал класс на слайде. Теперь нам не нужен никакой 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);
        }
      }
    }
  }
}

Вы могли заметить, что все привязанные запросы состояния CSS ведут себя как scrollsnapchanging , а не как scrollsnapchange . Это дает вам самый ранний крючок для обеспечения визуальной обратной связи привязываемого элемента. Если он слишком нетерпелив, рассмотрите событие JavaScript.

Прокручиваемый

Запрос состояния прокрутки будет очень полезен для демонстрации визуальных возможностей того, когда область прокрутки действительно можно прокручивать. До получения запросов о состоянии прокрутки эту информацию было сложно узнать .

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

Полный список синтаксиса

Обозначить прокрутку тенями

Леа Веру использует знаменитый CSS-трюк , который использует background-attachment: local для достижения эффекта, подобного этому, а также способ сделать это с помощью анимации, управляемой прокруткой . У каждого метода есть свои компромиссы, и нам предстоит выяснить, когда и где каждый из этих методов подходит лучше всего.

В следующем примере используется один липкий элемент, охватывающий область прокрутки. Непрозрачность градиента вверху и градиента внизу анимируется с помощью @property когда применяется контекстный запрос состояния прокрутки: @container scroll-state(scrollable: top) .

Также обратите внимание, что это первый контейнер, который одновременно является контейнером size и 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%);
    }
  }
}

Подсказка со стрелкой

Иногда отображение стрелки может помочь пользователям обнаружить, что область можно прокручивать. Они, как правило, указывают направление, в котором может происходить прокрутка, и исчезают, когда они больше не нужны. Вы можете сделать это с помощью следующего кода.

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

Вернуться наверх

Еще одно популярное взаимодействие с состоянием прокрутки — это удобная кнопка «прокрутить вверх». Следующий код приводит к исчезновению кнопки прокрутки вверх, когда прокручивать вверх некуда.

Это решение немного перевернуто, но позволяет уменьшить количество CSS. Естественное место расположения кнопки видно, поэтому вам нужно указать ей, чтобы она скрывалась, когда больше некуда прокручивать вверх.

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

Продолжение исследования

Если вы ищете больше, вот несколько ресурсов, которые варьируются от подробностей спецификаций до других замечательных статей по этой теме: