滾動敘事

Scrollytelling Stage

左側 sticky 數據舞台+右側步驟文章的雙欄滾動敘事,舞台圖形狀態、高亮區域與註解標線依步驟索引補間 morph 切換。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add "https://webberui.com/r/scrollytelling-stage.json?t=<安裝 token>"

還沒有專案,或安裝遇到問題?看快速開始 →

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

100
16
編輯中的呼叫預設屬性
<ScrollytellingStage/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add "https://webberui.com/r/scrollytelling-stage.json?t=<安裝 token>"

或在 components.json 設定 registries 後,改用 @webberui/scrollytelling-stage 安裝。

使用

每個 ScrollytellingStep 用 scene 描述捲到該步驟時左側舞台應呈現的狀態;捲動時舞台會在相鄰步驟的場景之間補間 morph。

import {
  ScrollytellingStage,
  ScrollytellingStep,
} from "@/components/ui/scrollytelling-stage";

<ScrollytellingStage>
  <ScrollytellingStep title="平穩起步" scene={{ data: [30, 42, 38, 46, 40] }}>
    <p>基準線:各週活躍度大致持平。</p>
  </ScrollytellingStep>

  <ScrollytellingStep
    title="週中放量"
    scene={{
      data: [30, 55, 74, 60, 44],
      annotation: { at: 2, label: "週三高峰" },
    }}
  >
    <p>推出新功能後,週三出現單日高峰。</p>
  </ScrollytellingStep>

  <ScrollytellingStep
    title="後段承接"
    scene={{
      data: [34, 58, 70, 82, 76],
      highlight: [3, 4],
      annotation: { at: 3, label: "維持在高檔" },
    }}
  >
    <p>高亮區間顯示週四、週五站上新高。</p>
  </ScrollytellingStep>
</ScrollytellingStage>;

若捲動發生在固定高度的巢狀 overflow-y-auto 容器內,把容器的 ref 傳給 container:

const scrollerRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
  <ScrollytellingStage container={scrollerRef}>
    {/* ...steps */}
  </ScrollytellingStage>
</div>;

需要完全自訂舞台時,改用 renderStage(取代內建資料圖);它會收到目前 activeIndex 與連續步進的 progress(MotionValue,0 至 步數-1):

<ScrollytellingStage
  renderStage={({ activeIndex, progress }) => (
    <MyCustomStage step={activeIndex} progress={progress} />
  )}
>
  {/* ...steps */}
</ScrollytellingStage>

Props

ScrollytellingStage

Prop型別預設值說明
childrenReactNode—一組 ScrollytellingStep
containerRefObject<HTMLElement | null>—巢狀 overflow 捲動容器的 ref;省略則以視窗為捲動容器
maxValuenumber100數值上限,長條高度以此正規化
stickyTopnumber16左側舞台吸頂位置(px)
renderStage(state) => ReactNode—自訂舞台渲染,收到 { activeIndex, progress }
classNamestring—外層容器 class
stageClassNamestring—左側舞台外框 class;以 text-* 設定強調色

ScrollytellingStep

Prop型別預設值說明
sceneStageScene—此步驟對應的舞台狀態(見下)
titleReactNode—步驟標題
childrenReactNode—步驟正文
classNamestring—步驟外層 class

StageScene

欄位型別說明
datanumber[]各長條數值,依 maxValue 正規化為高度
highlight[number, number]高亮區間 [起始索引, 結束索引](含端點,可為小數);省略則不顯示
annotation{ at: number; label: string }註解標線指向第 at 根長條並顯示 label;省略則不顯示

細節

  • 以 useScroll 追蹤右側步驟欄的捲動進度,換算成連續步進值(0 至 步數-1)作為所有補間的唯一驅動來源,因此長條高度、高亮帶與註解標線的變形永遠同步。
  • 高亮帶與註解標線使用 currentColor,可透過 stageClassName 的 text-* 一次設定整體強調色。
  • 註解標線鄰近的長條會漸亮為強調色,形成隨捲動移動的聚光效果。
  • 缺少 highlight 或 annotation 的場景,對應圖元會平滑淡出,morph 不會跳動。

可及性

  • 使用者系統開啟「減少動態效果」時,舞台改為逐步驟即時切換(不補間、不做過渡),版面與內容完全不變。
  • 左側舞台帶 role="img" 與描述目前步驟的 aria-label;內部 SVG 圖元對輔助科技隱藏。
  • 步驟為語意化的有序清單(<ol>/<li>),作用中步驟標記 aria-current="step",並以不透明度與標題強調;鍵盤沿用瀏覽器原生捲動即可依序閱讀。