Carousel

Набор компонентов для создания списков с прокруткой (галерей).

Storybook

Состав

При сборке карусели используйте структуру, в которой корневым элементом является Carousel со вложенными в него CarouselItem или CarouselCol. При необходимости отображения элементов карусели в сетке, оборачивайте карусель в CarouselGridWrapper.

CarouselGridWrapper

CarouselItem

CarouselCol

Использование

CSS Scroll Snap

  1. В компоненте Carousel укажите свойство scrollSnapType:
MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-web';

export const MyGallery = () = (
<Carousel scrollSnapType="mandatory">
// Элементы карусели помещаются здесь
</Carousel>
);
  1. Также укажите свойство scrollSnapAlign для элемента карусели:
MyGallery.tsx
import React from 'react';
import { CarouselItem } from '@salutejs/plasma-web';

export const MyGalleryItem = ({ children }) => (
<CarouselItem scrollSnapAlign="center">{children}</CarouselItem>
);

Определение центрального элемента

Карусель может определять активный элемент при прокрутке. Для этого укажите свойства detectActive, detectThreshold и обработчик onIndexChange:

MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-web';

export const MyGallery = () = (
<Carousel detectActive detectThreshold={0.5} onIndexChange={(index) => console.log(index)}>
// Элементы карусели помещаются здесь
</Carousel>
);

Стилизация центрального элемента

Элементы видимой части (viewport) можно стилизовать, например, увеличивать или менять *прозрачность.

В момент прокрутки карусели (с помощью колесика мыши, стрелок пульта или касанием) с определенной периодичностью вызывается обработчик скролла, который на основании положения элемента относительно viewport (внутренние границы карусели) вызывает тот или иной коллбек:

НазваниеОписаниеАргументыВозвращаемое значение
stylingCallbackОбработчик для элементов внутри viewport. Коллбек вызывается для видимого элемента, к нему применяется необходимая стилизация.itemEl: HTMLElement, slot: numbervoid
stylingResetCallbackОбработчик для элементов вне viewport. Элемент невидим, стилизация сбрасывается.itemEl: HTMLElementvoid

Для обозначения позиции элемента внутри viewport, карусель использует значение slot:

  • 0 равен центральному элементу;
  • -1 и 1 первый слева и справа от центрального;
  • -2 и 2 и т.д., соответственно, для второго и далее.
MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-web';

/**
* Функция увеличения центрального элемента.
* Предположим, что у нас 5 элементов во `viewport`.
* Тогда ряд slots будет таким: -2 -1 0 1 2.
* Центральный элемент примет opacity = 1, боковые - opacity = 0.5, а крайние слева и справа - opacity = 0
*/
const stylingCallback = (itemEl: HTMLDivElement, slot: number) => {
itemEl.style.opacity = `${1 - Math.abs(slot) / 2}`;
};

/**
* Функция сброса стилей элементов вне `viewport`.
*/
const stylingResetCallback = (itemEl: HTMLDivElement) => {
itemEl.style.opacity = '';
};

export const MyGallery = () = (
<Carousel stylingCallback={stylingCallback} stylingResetCallback={stylingResetCallback}>
// Элементы карусели помещаются здесь
</Carousel>
);
  • В данном примере используются Grid и CSS Scroll Snap.
  • В качестве основного блока разметки контейнер (Container), а колонки (Col) помещаются в строки (Row).
  • Карусель поддерживает определение (detectActive) активного элемента.
Live Editor

Result

Доступность

Для достижения доступности карусели необходимо выполнить слежующие условия:

  1. в элемент карусели добавьте атрибут aria-label, со значением, обозначающим текущую позицию в списке;
  2. разместите кнопки "назад" и "вперед" для навигации по карусели;
  3. укажите корректный атрибут id для секции карусели.
<section id="carousel-example">
<Button text="Prev" aria-controls="carousel-example" />
<Button text="Next" aria-controls="carousel-example" />
<Carousel>
{items.map((item, i) => <CarouselItem aria-label={`${i + 1} из ${items.length}`} />)}
</Carousel>
</section>