Section Snap Pin
區段釘選 + 吸附滾動編排:全高區段逐一吸附填滿視口,內容依序進場與退場,並附側邊導覽點。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<SectionSnapPin />
安裝
npx shadcn@latest add https://webberui.com/r/section-snap-pin.json或在 components.json 設定 registries 後,改用 @webberui/section-snap-pin 安裝。
安裝依賴後,從 registry JSON(/r/section-snap-pin.json 的 files[0].content)複製 section-snap-pin.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
SectionSnapPin 本身即為一個垂直吸附捲動容器,請為它設定固定高度(例如 h-[80vh] 或 h-screen)。內部放入多個 SnapSection,每個區段再以 SnapReveal 包住要編排進場的元素。
import {
SectionSnapPin,
SnapSection,
SnapReveal,
} from "@/components/ui/section-snap-pin";
<SectionSnapPin className="h-screen">
<SnapSection label="概覽" className="bg-neutral-950 text-white">
<SnapReveal order={0}>
<span className="text-xs tracking-widest uppercase">01</span>
</SnapReveal>
<SnapReveal order={1}>
<h2 className="text-4xl font-semibold">吸附式區段</h2>
</SnapReveal>
</SnapSection>
<SnapSection label="編排" className="bg-indigo-600 text-white">
<SnapReveal order={0} from="left">
<h2 className="text-4xl font-semibold">依序進場</h2>
</SnapReveal>
</SnapSection>
</SectionSnapPin>Props
SectionSnapPin
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | — | 一個或多個 SnapSection |
snap | "mandatory" | "proximity" | "mandatory" | 吸附強度 |
indicator | boolean | true | 是否顯示側邊區段導覽點 |
indicatorPosition | "left" | "right" | "right" | 導覽點位置 |
onActiveChange | (index: number) => void | — | 吸附區段切換時回呼 |
aria-label | string | "區段吸附捲動" | 捲動區的無障礙標籤 |
className | string | — | 最外層容器(設定固定高度) |
SnapSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | — | 區段內容,通常放入數個 SnapReveal |
label | string | — | 區段名稱:作為導覽點提示與無障礙標籤 |
align | "start" | "center" | "end" | "center" | 內容在區段內的垂直對齊 |
className | string | — | 附加樣式(背景、文字色等) |
SnapReveal
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | — | 要編排進場的內容 |
order | number | 0 | 進場順序,乘上 stagger 得延遲 |
from | "up" | "down" | "left" | "right" | "none" | "up" | 進場位移方向 |
distance | number | 24 | 進場位移距離(px) |
stagger | number | 0.08 | 每階順序的間隔(秒) |
duration | number | 0.6 | 單一單位動畫時長(秒) |
className | string | — | 附加樣式 |
細節
SectionSnapPin使用 CSS Scroll Snap(snap-y+snap-mandatory/snap-proximity)達成吸附,捲動效能交給瀏覽器原生處理。- 每個
SnapSection以IntersectionObserver(root 為捲動容器)判斷自己是否超過 55% 可見,成為主要區段;此狀態透過 context 傳給內部SnapReveal觸發進場,離開時退場,因此重新捲入會再次編排。 - 側邊導覽點旁的細軌以
useScroll追蹤容器捲動進度即時填充。 - 捲動容器的原生捲軸以樣式隱藏,改由吸附與導覽點提供位置感。
可及性
- 捲動容器帶
role="region"、aria-label與tabIndex,可用鍵盤聚焦後以↑/↓、PageUp/PageDown、Home/End切換區段。 - 導覽點為原生
<button>,帶aria-label(採用區段label)與aria-current,可鍵盤操作並顯示提示。 - 使用者系統開啟「減少動態效果」時,平滑捲動改為即時跳轉,
SnapReveal直接渲染靜態內容、不做進場位移。