scroll-snap-type

스크롤 스냅을 활성화합니다. sstxm은 수평 캐러셀에, sstym은 수직 페이지 스냅에 사용합니다.

클래스 목록

클래스CSS설명
sstnscroll-snap-type: none스크롤 스냅 비활성화
sstxmscroll-snap-type: x mandatory수평 필수 스냅
sstymscroll-snap-type: y mandatory수직 필수 스냅
sstbmscroll-snap-type: both mandatory양방향 필수 스냅
sstxpscroll-snap-type: x proximity수평 근접 스냅
sstypscroll-snap-type: y proximity수직 근접 스냅
sstbpscroll-snap-type: both proximity양방향 근접 스냅

라이브 데모

아래 컨테이너를 좌우로 스크롤한 뒤 손을 떼 보세요. 버튼으로 스냅 타입을 바꾸면 멈추는 위치가 달라집니다.

슬라이드 1
슬라이드 2
슬라이드 3
슬라이드 4
슬라이드 5
슬라이드 6

sstxm — 스크롤이 끝나면 항상 가장 가까운 카드의 시작점으로 끌려갑니다.

클래스별 상세

sstnscroll-snap-type: none

스냅을 끕니다. 자식에 scroll-snap-align이 남아 있어도 무시되므로, 특정 뷰포트에서만 캐러셀 스냅을 해제하고 싶을 때 반응형 프리픽스와 함께 쓰기 좋습니다.

<!-- Free scrolling: stops wherever the user releases -->
<div class="sstn df oxa gap16px">
  <div class="fs0 w28rem h20rem bg18181B br8px"></div>
  <div class="fs0 w28rem h20rem bg18181B br8px"></div>
</div>

sstxmscroll-snap-type: x mandatory

가로축 필수 스냅. 카드 캐러셀, 이미지 갤러리, 스토리 뷰어처럼 항상 한 카드가 딱 맞게 보여야 하는 UI의 기본 선택지입니다. 컨테이너에는 overflow-x가, 자식에는 scroll-snap-align이 반드시 필요합니다.

<!-- Horizontal carousel: container + children both required -->
<div class="sstxm df oxa gap16px">
  <div class="ssas fs0 w28rem h20rem bg18181B br8px">Slide 1</div>
  <div class="ssas fs0 w28rem h20rem bg18181B br8px">Slide 2</div>
  <div class="ssas fs0 w28rem h20rem bg18181B br8px">Slide 3</div>
</div>

sstymscroll-snap-type: y mandatory

세로축 필수 스냅. 화면 전체를 차지하는 섹션을 한 화면씩 넘기는 랜딩페이지나 숏폼 피드에 사용합니다. 아래 데모를 세로로 스크롤해 보세요.

<!-- Full-screen vertical section snap -->
<div class="sstym oya h100vh">
  <section class="ssas h100vh df jcc aic">Section 1</section>
  <section class="ssas h100vh df jcc aic">Section 2</section>
  <section class="ssas h100vh df jcc aic">Section 3</section>
</div>

세로 스냅 데모 (컨테이너 안에서 스크롤)

섹션 1
섹션 2
섹션 3
섹션 4

sstbmscroll-snap-type: both mandatory

가로·세로 양쪽 모두 스냅합니다. 지도 타일, 좌석 배치도, 대형 표처럼 2차원으로 이동하는 뷰에서만 의미가 있습니다. 두 축 모두 스크롤 가능해야 효과가 보입니다.

<!-- 2D map / spreadsheet style grid snapping -->
<div class="sstbm oa w100p h40rem">
  <div class="df">
    <div class="ssas fs0 w40rem h40rem bg18181B"></div>
    <div class="ssas fs0 w40rem h40rem bg1E1E2E"></div>
  </div>
</div>

sstxpsstypsstbpproximity

근접 스냅은 사용자가 스냅 포인트 근처에서 멈췄을 때만 정렬합니다. 항목 높이가 제각각이거나 긴 글이 섞여 있어 필수 스냅이 답답하게 느껴지는 경우에 적합합니다.

<!-- Proximity: snaps only when the scroll ends near a snap point -->
<div class="sstxp df oxa gap16px">
  <div class="ssas fs0 w28rem h20rem bg18181B br8px"></div>
  <div class="ssas fs0 w28rem h20rem bg18181B br8px"></div>
  <div class="ssas fs0 w28rem h20rem bg18181B br8px"></div>
</div>

mandatory vs proximity

타입동작
mandatory스크롤이 끝나면 반드시 스냅 포인트에 정렬됩니다
proximity스냅 포인트 근처일 때만 정렬됩니다

사용 예시

scroll-snap-type은 스크롤 컨테이너에 적용하며, 자식 요소에 scroll-snap-align을 함께 사용합니다.

<!-- Horizontal carousel -->
<div class="df sstxm oxa">
  <div class="fs0 w100p ssas">Slide 1</div>
  <div class="fs0 w100p ssas">Slide 2</div>
  <div class="fs0 w100p ssas">Slide 3</div>
</div>

<!-- Vertical page snap -->
<div class="sstym oya h100vh">
  <section class="h100vh ssas">Section 1</section>
  <section class="h100vh ssas">Section 2</section>
</div>

실전 예시: 상품 캐러셀

스냅 컨테이너에 스크롤 패딩과 overscroll 제어를 함께 걸면, 카드가 화면 가장자리에 붙지 않고 스와이프가 뒤쪽 페이지로 새지 않습니다.

<!-- Product gallery with a sticky header -->
<header class="ps t0 h6rem bg18181B df aic px2rem">Shop</header>

<!-- spl2rem / spr2rem inset the snap position from the edges,
     obxc keeps the swipe from scrolling the page behind -->
<div class="sstxm spl2rem spr2rem obxc swt df oxa gap16px py2rem">
  <article class="ssas fs0 w28rem br8px oh bg18181B">
    <img src="/p1.jpg" alt="" class="w100p h20rem ofc">
    <div class="p16px">
      <h3 class="fs16px fw600 cFAFAFA">Product 1</h3>
      <p class="fs14px c71717A">$29</p>
    </div>
  </article>
  <article class="ssas fs0 w28rem br8px oh bg18181B">
    <img src="/p2.jpg" alt="" class="w100p h20rem ofc">
    <div class="p16px">
      <h3 class="fs16px fw600 cFAFAFA">Product 2</h3>
      <p class="fs14px c71717A">$39</p>
    </div>
  </article>
</div>

주의사항

컨테이너와 자식 둘 다 필요합니다

컨테이너의 scroll-snap-type만 걸고 자식에 scroll-snap-align을 빼먹으면 아무 일도 일어나지 않습니다. 스냅이 안 될 때 가장 흔한 원인입니다.

스크롤이 실제로 발생해야 합니다

컨테이너에 oxa·oya 같은 overflow와, 내용이 넘칠 만한 크기가 있어야 합니다. flex 자식에는 fs0을 줘서 줄어들지 않게 하세요.

mandatory는 접근성을 해칠 수 있습니다

필수 스냅은 스냅 포인트 사이에 있는 콘텐츠를 사용자가 볼 수 없게 만들 수 있습니다. 항목이 뷰포트보다 클 가능성이 있다면 proximity를 쓰거나 항목 높이를 제한하세요.

가장자리 여백은 scroll-padding으로

스냅된 카드가 컨테이너 가장자리에 딱 붙어 답답해 보인다면 컨테이너에 spl2rem 같은 scroll-padding을, 개별 카드에는 sml2rem 같은 scroll-margin을 사용하세요.