AnimateMarquee
내용이 끝없이 한쪽으로 흘러가는 효과입니다. 내용을 두 벌 깔고 각 벌이 정확히 자기 길이만큼 이동하므로, 이음매도 없고 띠가 비는 프레임도 없습니다.
tsx
import { AnimateMarquee } from 'neba';
<AnimateMarquee speed={45} gap="1.5rem">
{customers.map((name) => (
<Chip key={name}>{name}</Chip>
))}
</AnimateMarquee>;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| orientation공통 | 'horizontal' | 'vertical' | 'horizontal' | 흐르는 방향의 축 |
| reverse | boolean | false | 반대 방향으로 흐릅니다 |
| speed | number | 60 | 초당 이동 픽셀. 시간이 아니라 속도이므로, 짧은 띠와 긴 띠가 같은 속도로 흐릅니다 |
| gap | number | string | '2rem' | 항목 사이, 그리고 한 바퀴의 끝과 다음 시작 사이의 간격 |
| copies | number | 2 | 이어 붙이는 복제본 수. 내용이 상자보다 짧아 빈 구간이 생길 때만 올리면 됩니다 |
| pauseOnHover | boolean | true | 포인터가 올라가 있거나 안쪽에 focus가 있는 동안 멈춥니다. 지나가는 내용은 클릭할 수 없기 때문입니다 |
| duration공통 | number | — | 한 번 재생되는 시간(ms) |
| delay공통 | number | 0 | 시작 전 대기(ms) |
| easing | string | — | CSS 이징 곡선. 기본값은 라이브러리의 곡선 |
| repeat공통 | number | 'infinite' | 'infinite' | 반복 횟수 |
| alternate공통 | boolean | false | 한 번 걸러 거꾸로 재생합니다. 반복이 처음으로 튀지 않고 되돌아옵니다 |
| trigger공통 | 'mount' | 'visible' | 'hover' | 'manual' | 'mount' | 무엇이 재생을 시작하는지. visible은 화면에 들어올 때, hover는 포인터가 올라올 때(포커스 포함), manual은 play가 정합니다 |
| play | boolean | — | trigger가 manual일 때 재생합니다. false → true 될 때마다 처음부터 다시 시작합니다 |
| once공통 | boolean | true | trigger가 visible일 때 처음 한 번만 재생할지. 끄면 화면에 들어올 때마다 다시 재생됩니다 |
| threshold공통 | number | 0.2 | trigger가 visible일 때 화면에 얼마나 들어와야 하는지, 0에서 1 사이 |
| paused공통 | boolean | false | 있는 자리에 붙들어 둡니다 |
| children | ReactNode | — | 흘러가는 것들 |
나머지 <div> 속성은 모두 루트로 전달됩니다. 모든 Animate*가 공유하는 설정은 Prop 규약에 있습니다.
예시
speed와 reverse
띠 자신의 너비를 재어 계산하는 초당 픽셀입니다. 그래서 로고 네 개와 마흔 개가 같은 속도로 흐르고, 긴 쪽이 흐릿해지지 않습니다. duration도 받으며 측정값보다 우선합니다. reverse는 반대 방향으로 흘립니다.
orientation
vertical은 띠를 가로가 아니라 세로로 흘립니다. 로그나 활동 피드에 씁니다. 흐를 자리가 있으려면 상자에 높이가 있어야 합니다.
pauseOnHover
기본으로 켜져 있고, 장식이 아닙니다. 포인터 앞을 지나가는 내용은 안정적으로 클릭할 수 없고, 멈추지 않는 띠 안의 링크는 아무도 따라갈 수 없는 링크입니다. 포인터뿐 아니라 focus에도 반응하므로, 탭으로 도달한 링크 역시 흐르지 않습니다.
copies와 gap
gap은 항목 사이의 간격이자, 한 바퀴의 마지막 항목과 다음 바퀴의 첫 항목 사이의 간격입니다. copies는 내용을 몇 번 이어 붙이는지입니다. 컨테이너만큼 넓은 내용이라면 둘이면 충분하고, 내용이 짧아 뒤에 빈 구간이 생길 때 올리면 됩니다.
tsx
<AnimateMarquee copies={4} gap="3rem">
<Chip>짧은 항목 하나</Chip>
</AnimateMarquee>접근성
- 첫 번째 벌만 읽힙니다. 나머지는
aria-hidden인데, 그렇지 않으면 스크린 리더가 띠 전체를 깔린 횟수만큼 읽게 됩니다. - 축소된 모션 설정에서는 띠가 멈추고 내용은 제자리에 놓입니다.
pauseOnHover가 그 안의 상호작용 요소를 쓸 수 있게 만드는 것이고, 포인터가 띠 위에 있을 때와 focus가 안쪽에 들어왔을 때를 모두 덮습니다. 링크나 버튼이 든 띠에서는 끄지 마세요.