Управление маркерами CSS-каруселей
После релиза CSS-каруселей в Chrome 135 перед Google I/O в прошлом году и критики доступности, новостей о развитии этого API как-то не было. Но в Chrome 140 и Chrome 154 (и соответствующих версиях Edge) CSS-карусели были немного улучшены.
Я делал пост о CSS-каруселях. Напомню, что это возможность добавить контейнеру с прокруткой кнопки «вперёд» и «назад», а также группу с маркерами (пагинацию) с помощью CSS. В сочетании со Scroll Snap получаются карусели без JS.
.carousel {
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-marker-group: after;
scrollbar-width: none;
[data-slide] {
scroll-snap-align: center;
}
[data-slide]::scroll-marker {
/* Резервное значение */
content: attr(data-slide);
content: sibling-index();
}
[data-slide]::scroll-marker:target-current {
background: var(--accent);
}
&::scroll-button(left) {
content: "←" / "Previous";
}
&::scroll-button(right) {
content: "→" / "Next";
}
&::scroll-button(*):focus-visible {
outline-offset: 5px;
}
}
Одна из претензий к CSS-каруселям — создание интерактивных элементов в CSS. Кнопки, маркеры и их обёртка создаются в виде интерактивных псевдо-элементов что не даёт полного контроля и принуждает использовать content в CSS.
При просмотре в DevTools у карусели из примера выше получается такая структура:
::scroll-button(left)
::scroll-button(right)
::scroll-marker-group
::scroll-marker
::scroll-marker
::scroll-marker
Внутри списка создаются псевдо-элементы ::scroll-button(*) — кнопки «вперёд» и «назад», ::scroll-marker-group — контейнер для маркеров с ролью navigation и ::scroll-marker — сами маркеры с ролью link.
Эту структуру с псевдо-элементами можно выразить в виде HTML-эквивалента для понимания итоговой семантики и связей элементов. Кнопки выносятся перед списком слайдов, а контейнер с маркерами в виде и после списка.
←
→
href="[ссылается на li data-slide='1']"
aria-details="[ссылается на li data-slide='1']"
>
1
href="[ссылается на li data-slide='2']"
aria-details="[ссылается на li data-slide='2']"
>
2
href="[ссылается на li data-slide='3']"
aria-details="[ссылается на li data-slide='3']"
>
3
По умолчанию контейнер с маркерами получает роль navigation, а сами маркеры — роль link. Работает это, соответственно, как с набором внутри. Изменить это поведение можно с помощью новых значений scroll-marker-group.
Значения links и tabs идут в дополнение к уже существующим значениям before и after, которые определяют визуальное положение группы маркеров. links и tabs определяют тип группы:
- links: у контейнера маркеров будет роль navigation, у маркеров будет роль link и они будут вести себя как якорные ссылки, табуляция по ссылкам будет последовательная;
- tabs: у контейнера маркеров будет роль tablist, у маркеров будет роль tab и они будут вести себя как вкладки, табуляция попадает только на активную вкладку, а навигация между вкладками с помощью стрелок.
.carousel {
/* ... */
scroll-marker-group: after tabs;
}
1
2
3
Контейнер меняет роль с navigation на tablist, а маркеры с link на tab. Так как tablist — это виджет, который требует клавиатурной навигации, браузер автоматически добавляет навигацию стрелками между маркерами.
Второй способ управления группой маркеров — возможность выноса в HTML. У элемента внутри карусели можно указать свойство scroll-target-group: auto и тогда он будет использоваться в качестве контейнера для маркеров.
Чтобы это работало аналогично группе в CSS, внутри контейнера должны быть якорные ссылки, которые станут аналогом псевдо-элементов ::scroll-marker. Для них браузер автоматически вычислит состояние :target-current.
1
2
3
.carousel {
/* ... */
.markers {
scroll-target-group: auto;
a:target-current {
background-color: var(--accent);
}
}
}
По большей части это предназначено для интерактивного содержания, а не карусели. Маркеры по шаблону карусели должны быть сочетанием tablist и tab. Если вместо ссылок будут другие элементы, то автоматика браузера не сработает.
В теории это можно решить с помощью focusgroup и ARIA, добавив клавиатурное поведение и семантику. Но от встроенного решения я жду отсутствия необходимости указывать какие-либо атрибуты ARIA для доступности.
href="#slide-1"
role="tab"
aria-controls="slide-1"
aria-details="slide-1"
>
1
Теперь есть как минимум два способа управления клавиатурной навигацией и семантикой контейнера с маркерами. Это хорошо, но всё ещё к интерактивным псевдо-элементам в CSS остаются вопросы. Идея использовать реальные кнопки звучит лучше.
#css #ui
После релиза CSS-каруселей в Chrome 135 перед Google I/O в прошлом году и критики доступности, новостей о развитии этого API как-то не было. Но в Chrome 140 и Chrome 154 (и соответствующих версиях Edge) CSS-карусели были немного улучшены.
Я делал пост о CSS-каруселях. Напомню, что это возможность добавить контейнеру с прокруткой кнопки «вперёд» и «назад», а также группу с маркерами (пагинацию) с помощью CSS. В сочетании со Scroll Snap получаются карусели без JS.
.carousel {
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-marker-group: after;
scrollbar-width: none;
[data-slide] {
scroll-snap-align: center;
}
[data-slide]::scroll-marker {
/* Резервное значение */
content: attr(data-slide);
content: sibling-index();
}
[data-slide]::scroll-marker:target-current {
background: var(--accent);
}
&::scroll-button(left) {
content: "←" / "Previous";
}
&::scroll-button(right) {
content: "→" / "Next";
}
&::scroll-button(*):focus-visible {
outline-offset: 5px;
}
}
Одна из претензий к CSS-каруселям — создание интерактивных элементов в CSS. Кнопки, маркеры и их обёртка создаются в виде интерактивных псевдо-элементов что не даёт полного контроля и принуждает использовать content в CSS.
При просмотре в DevTools у карусели из примера выше получается такая структура:
::scroll-button(left)
::scroll-button(right)
::scroll-marker-group
::scroll-marker
::scroll-marker
::scroll-marker
Внутри списка создаются псевдо-элементы ::scroll-button(*) — кнопки «вперёд» и «назад», ::scroll-marker-group — контейнер для маркеров с ролью navigation и ::scroll-marker — сами маркеры с ролью link.
Эту структуру с псевдо-элементами можно выразить в виде HTML-эквивалента для понимания итоговой семантики и связей элементов. Кнопки выносятся перед списком слайдов, а контейнер с маркерами в виде и после списка.
←
→
href="[ссылается на li data-slide='1']"
aria-details="[ссылается на li data-slide='1']"
>
1
href="[ссылается на li data-slide='2']"
aria-details="[ссылается на li data-slide='2']"
>
2
href="[ссылается на li data-slide='3']"
aria-details="[ссылается на li data-slide='3']"
>
3
По умолчанию контейнер с маркерами получает роль navigation, а сами маркеры — роль link. Работает это, соответственно, как с набором внутри. Изменить это поведение можно с помощью новых значений scroll-marker-group.
Значения links и tabs идут в дополнение к уже существующим значениям before и after, которые определяют визуальное положение группы маркеров. links и tabs определяют тип группы:
- links: у контейнера маркеров будет роль navigation, у маркеров будет роль link и они будут вести себя как якорные ссылки, табуляция по ссылкам будет последовательная;
- tabs: у контейнера маркеров будет роль tablist, у маркеров будет роль tab и они будут вести себя как вкладки, табуляция попадает только на активную вкладку, а навигация между вкладками с помощью стрелок.
.carousel {
/* ... */
scroll-marker-group: after tabs;
}
1
2
3
Контейнер меняет роль с navigation на tablist, а маркеры с link на tab. Так как tablist — это виджет, который требует клавиатурной навигации, браузер автоматически добавляет навигацию стрелками между маркерами.
Второй способ управления группой маркеров — возможность выноса в HTML. У элемента внутри карусели можно указать свойство scroll-target-group: auto и тогда он будет использоваться в качестве контейнера для маркеров.
Чтобы это работало аналогично группе в CSS, внутри контейнера должны быть якорные ссылки, которые станут аналогом псевдо-элементов ::scroll-marker. Для них браузер автоматически вычислит состояние :target-current.
1
2
3
.carousel {
/* ... */
.markers {
scroll-target-group: auto;
a:target-current {
background-color: var(--accent);
}
}
}
По большей части это предназначено для интерактивного содержания, а не карусели. Маркеры по шаблону карусели должны быть сочетанием tablist и tab. Если вместо ссылок будут другие элементы, то автоматика браузера не сработает.
В теории это можно решить с помощью focusgroup и ARIA, добавив клавиатурное поведение и семантику. Но от встроенного решения я жду отсутствия необходимости указывать какие-либо атрибуты ARIA для доступности.
href="#slide-1"
role="tab"
aria-controls="slide-1"
aria-details="slide-1"
>
1
Теперь есть как минимум два способа управления клавиатурной навигацией и семантикой контейнера с маркерами. Это хорошо, но всё ещё к интерактивным псевдо-элементам в CSS остаются вопросы. Идея использовать реальные кнопки звучит лучше.
#css #ui