Motion
스크롤 훅
stable스크롤 이벤트에 반응하는 뷰포트 감지, 진행률, 방향 감지 훅
@hua-labs/motion-corev2.0.0
Import
import {
useScrollReveal,
useScrollProgress,
useScrollDirection,
useScrollToggle,
useScrollPositionToggle,
} from '@hua-labs/motion-core'useScrollReveal
요소가 스크롤되어 뷰포트에 진입할 때 지정한 모션 타입으로 애니메이션을 트리거한다.
Signature
function useScrollReveal<T extends MotionElement = HTMLDivElement>(
options?: ScrollRevealOptions
): BaseMotionReturn<T>Parameters
| 파라미터 | 타입 | 기본값 | 설명 |
|---|---|---|---|
motionType | ScrollRevealMotionType | 'fadeIn' | 애니메이션 타입 |
threshold | number | 프로필 기본값 | Intersection Observer 임계값 (0-1) |
rootMargin | string | '0px' | IntersectionObserver rootMargin |
triggerOnce | boolean | 프로필 기본값 | 한 번만 트리거 |
duration | number | 프로필 기본값 | 지속 시간 (ms) |
delay | number | 0 | 지연 시간 (ms) |
easing | string | 프로필 기본값 | CSS 이징 |
ScrollRevealMotionType
type ScrollRevealMotionType =
| 'fadeIn'
| 'slideUp'
| 'slideLeft'
| 'slideRight'
| 'scaleIn'
| 'bounceIn'Usage
import { useScrollReveal } from '@hua-labs/motion-core'
function AnimatedSection() {
const { ref, style } = useScrollReveal({
motionType: 'slideUp',
delay: 100,
duration: 700
})
return <section ref={ref} style={style}>섹션 내용</section>
}useScrollProgress
페이지 전체 스크롤 진행률을 0~100 사이의 숫자로 반환한다.
Signature
function useScrollProgress(options?: ScrollProgressOptions): {
progress: number
mounted: boolean
}
interface ScrollProgressOptions {
target?: number // 목표 스크롤 높이 (기본값: document 전체 높이)
offset?: number // 시작 오프셋 (px)
showOnMount?: boolean
}Returns
| 이름 | 타입 | 설명 |
|---|---|---|
progress | number | 스크롤 진행률 (0~100) |
mounted | boolean | 클라이언트 마운트 여부 |
Usage
import { useScrollProgress } from '@hua-labs/motion-core'
function ProgressBar() {
const { progress, mounted } = useScrollProgress()
if (!mounted) return null
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
height: 3,
width: `${progress}%`,
background: 'cyan',
transition: 'width 100ms linear'
}}
/>
)
}useScrollDirection
현재 스크롤 방향을 감지한다. 네비게이션 바 숨김/표시 등에 활용한다.
Signature
function useScrollDirection(options?: ScrollDirectionConfig): {
direction: ScrollDirection
mounted: boolean
}
type ScrollDirection = 'up' | 'down' | 'idle'
interface ScrollDirectionConfig {
threshold?: number // 방향 변화를 감지할 최소 스크롤 거리 (기본값: 10)
idleDelay?: number // idle 상태로 전환 지연 시간 ms (기본값: 150)
showOnMount?: boolean
}Usage
import { useScrollDirection } from '@hua-labs/motion-core'
function Navbar() {
const { direction, mounted } = useScrollDirection({ threshold: 5 })
const isHidden = direction === 'down'
return (
<nav
style={{
transform: isHidden ? 'translateY(-100%)' : 'translateY(0)',
transition: 'transform 300ms ease'
}}
>
내비게이션
</nav>
)
}useScrollToggle
요소의 스크롤 위치에 따라 표시/숨김 상태를 전환하며 애니메이션을 적용한다.
Signature
function useScrollToggle<T extends MotionElement = HTMLDivElement>(
options?: ScrollToggleOptions
): BaseMotionReturn<T>
interface ScrollToggleOptions extends BaseMotionOptions {
showScale?: number // 표시 시 스케일 (기본값: 1)
showOpacity?: number // 표시 시 투명도 (기본값: 1)
showRotate?: number // 표시 시 회전 (deg, 기본값: 0)
showTranslateY?: number // 표시 시 Y 이동 (px, 기본값: 0)
showTranslateX?: number // 표시 시 X 이동 (px, 기본값: 0)
hideScale?: number // 숨김 시 스케일 (기본값: 0.8)
hideOpacity?: number // 숨김 시 투명도 (기본값: 0)
hideRotate?: number // 숨김 시 회전 (기본값: 0)
hideTranslateY?: number // 숨김 시 Y 이동 (기본값: 20)
hideTranslateX?: number // 숨김 시 X 이동 (기본값: 0)
scrollThreshold?: number // 임계값 비율 (0-1, 기본값: 0.1)
scrollDirection?: 'up' | 'down' | 'both' // 감지 방향 (기본값: 'both')
}Usage
import { useScrollToggle } from '@hua-labs/motion-core'
function FloatingButton() {
const { ref, style } = useScrollToggle({
scrollThreshold: 0.3,
scrollDirection: 'down',
hideOpacity: 0,
hideTranslateY: 30,
duration: 300
})
return (
<button ref={ref} style={style}>
위로 가기
</button>
)
}useScrollPositionToggle
window.pageYOffset가 설정한 임계값을 초과하면 가시성을 토글한다. "맨 위로 가기" 버튼 등에 활용한다.
Signature
function useScrollPositionToggle(options?: ScrollPositionToggleConfig): {
isVisible: boolean
scrollToTop: () => void
mounted: boolean
}
interface ScrollPositionToggleConfig {
threshold?: number // 스크롤 임계값 (px, 기본값: 400)
showOnMount?: boolean
smooth?: boolean // 부드러운 스크롤 여부 (기본값: true)
}Usage
import { useScrollPositionToggle } from '@hua-labs/motion-core'
function BackToTop() {
const { isVisible, scrollToTop, mounted } = useScrollPositionToggle({
threshold: 300
})
if (!mounted || !isVisible) return null
return (
<button onClick={scrollToTop}>
맨 위로
</button>
)
}Notes
useScrollReveal은sharedIntersectionObserver풀을 재사용하여 다수의 요소를 관찰해도 Observer 인스턴스가 최소화된다.useScrollProgress와useScrollToggle은 내부적으로sharedScroll구독 방식을 사용해scroll이벤트 리스너가 중복 등록되지 않는다.useScrollDirection의mounted상태를 확인한 후에direction값을 사용해야 SSR에서 안전하다.useScrollPositionToggle과useScrollToggle은 목적이 다르다.useScrollPositionToggle은 절대 스크롤 위치 기준,useScrollToggle은 요소의 뷰포트 내 위치 기준이다.