한 줄 요약
스크롤 방향을 인지해 아래로 내릴 땐 헤더가 비켜주고 위로 올릴 땐 다시 등장하는 패턴 — useScrollDirection 훅 + translate-y 트랜지션.
이럴 때 필요해요
긴 본문 페이지에서 상단 헤더가 늘 시야를 차지하면 답답하다. 토스·노션·인스타그램 웹뷰가 "아래로 내릴 땐 헤더 빠지고, 위로 올릴 땐 등장"하는 인터랙션을 쓰는 이유 — 글 읽기 모드와 네비게이션 모드를 사용자의 스크롤 의도로 구분해 주는 것.
어떻게 동작하나
- 방향 측정 — 방향은 위치의 시간 변화율이라 IntersectionObserver로 못 잡는다.
lastYRef에 직전 scrollY를 들고 현재값과 비교해 부호를 본다 (+면 down, -면 up). - rAF 스로틀 — scroll 이벤트는 프레임당 여러 번 발사되니
requestAnimationFrame+ ticking 플래그로 프레임당 한 번만 측정. listener는{ passive: true }. - threshold 히스테리시스 — 1px만 떨려도 방향이 바뀌면 헤더가 깜빡인다.
Math.abs(delta) ≥ threshold(기본 8px) 통과해야만 갱신. - topOffset 강제 노출 — 페이지 최상단에선 방향과 무관하게 헤더를 항상 노출. 막 도착했을 때 헤더가 없으면 길을 잃는다.
- CSS —
-translate-y-full↔translate-y-0,duration-300 ease-out.top:0이라야 슬라이드가 자연스럽다.
놓치기 쉬운 것
display:none토글은 금물 — 트랜지션이 끊긴다. 위치만 옮긴다.- sticky 컨테이너의 부모가
overflow: hidden이면 sticky가 안 잡힌다. - iOS Safari momentum scroll에서 방향이 끝물에 잠깐 반대로 잡히기도 — threshold를 12~16으로 키우면 거의 안 보인다.
- threshold가 너무 크면(20+) 위로 빠르게 올렸을 때 등장이 늦어 답답하다. 8~12이 sweet spot.
- 헤더 안에 드롭다운·메가메뉴가 있으면 헤더가 숨을 때 메뉴도 같이 닫는 처리가 필요하다.
이런 곳에 써요
- 모바일 본문 위주 페이지 — 블로그 상세, 뉴스 기사, 긴 마케팅 랜딩
- 콘텐츠 피드(인스타·X 웹) 상단 헤더
- 풀스크린 미디어 페이지의 컨트롤 자동 숨김
- 다단계 폼·온보딩의 진행률 바 — 본문 집중 모드 대응