Пример того о чем пойдет речь:
Card 1
Card 2
Card 3
CSS
Спецификация CSS Scroll Snap позволяет привязывать положение прокрутки к определённым элементам или местоположению после того, как пользователь прокрутил страницу или элемент.
.wrapper {
display: flex;
gap: 8px;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: scroll;
scroll-snap-type: x mandatory;
/* NOTE: [1/2] Если нужны первая и последняя по центру */
padding-left: 10%;
padding-right: 10%;
}
.wrapper::-webkit-scrollbar {
display: none;
}
.cardWrapper {
scroll-snap-align: center;
/* NOTE: [2/2] Если нужен хвост и перед, но [1/2] выключено */
min-width: 100%;
width: 100%;
}
.card {
height: 100%;
padding: 8px 8px 8px 8px;
border-radius: 8px;
font-size: small;
border: 1px solid #959eaa;
}
React-компонент с перелистыванием карочек
SubjobsExperimentalCards.tsx
import { CSSProperties, memo } from 'react'
import classes from './SubjobsExperimentalCards.module.scss'
const genericMemo: <T>(component: T) => T = memo
type TProps<T> = {
wrapperStyles?: CSSProperties;
items: T[];
cardRenderer: (ps: { itemData: T }) => React.ReactNode;
getItemKey: (itemData: T) => string;
}
function _SubjobsExperimentalCards<TItem>({
wrapperStyles,
items,
cardRenderer,
getItemKey,
}: TProps<TItem>) {
return (
<>
{
items.length > 0 && (
<div
style={wrapperStyles}
className={classes.wrapper}
>
{
items.map((item) => {
return (
<div
className={classes.cardWrapper}
key={getItemKey(item)}
>
{cardRenderer({ itemData: item })}
</div>
)
})
}
</div>
)
}
</>
)
}
export const SubjobsExperimentalCards = genericMemo(_SubjobsExperimentalCards)
Usage
<SubjobsExperimentalCards
items={[
{ id: 1 }
]}
cardRenderer={({ itemData }) => (
return (
<div>{itemData.id}</div>
)
)}
getItemKey={(item) => String(item.id)}
/>
See also