版面構圖

紙片分層場景

3 到 5 層撕邊紙片疊成的場景,隨捲動或游標做分層視差,每層有柔和紙張陰影與不規則撕邊,適合故事型首頁與編輯排版。

把 3 到 5 張撕邊紙片由後到前疊成一個場景:每張紙片有自己的顏色、以 seed 確定性產生的不規則撕邊、沿撕邊形狀投下的柔和紙張陰影,以及可選的紙纖維紋理。捲動頁面或移動游標時,越前面的紙片位移越多,形成剪紙繪本般的分層視差。每層可放自畫 SVG 或文字,最上層的 children 是正常可讀的標題區,適合故事型首頁與編輯排版。

把這個效果裝進你的專案

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

npx webberui@latest add paper-layers-scene

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

Playground

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

18
120
3
編輯中的呼叫預設屬性
<PaperLayersScene/>

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

安裝

npx webberui@latest add https://webberui.com/r/paper-layers-scene.json

或在 components.json 設定 registries 後,改用 @webberui/paper-layers-scene 安裝。

使用

import { PaperLayersScene } from "@/components/ui/paper-layers-scene";

<PaperLayersScene
  mode="both"
  layers={[
    { id: "far", color: "#efe7da", height: "74%" },
    { id: "mid", color: "#e2d4bd", height: "56%" },
    { id: "near", color: "#c2ab8a", height: "36%", tornEdge: "both" },
    { id: "front", color: "#97805c", height: "18%", content: <MyGrassSvg /> },
  ]}
>
  <h2 className="pt-10 text-center text-3xl font-semibold">慢慢讀的週末</h2>
</PaperLayersScene>

放在巢狀捲動容器內

預設追蹤的是視窗的捲動。若元件放在固定高度的 overflow-y-auto 容器內,請把該容器的 ref 傳給 container。mode 含 scroll 時,分層視差跟著場景在容器內的捲動進度走。

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

<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
  <PaperLayersScene container={scrollerRef} />
</div>

以整個視窗為捲動容器時可省略 container,行為與原本相同。

Props

Prop型別預設值說明
layersPaperLayer[]四層預設暖色紙由後到前疊放的紙片層,建議 3 到 5 層
mode"scroll" | "pointer" | "both""both"視差驅動來源;觸控裝置上 pointer 停用,只留 scroll
intensitynumber18游標視差強度(px),depth = 1 的層在游標移到邊緣時的最大位移
rangenumber120捲動視差距離(px),depth = 1 的層在整段捲動過程中的總位移
stiffnessnumber120游標視差 spring 剛性,越大跟隨越即時
dampingnumber20游標視差 spring 阻尼,越小回位餘晃越明顯
seednumber3撕邊亂數種子,同一個 seed 永遠產生同樣的撕邊
grainbooleantrue是否疊上紙纖維紋理(multiply 6%)
aspectRatiostring"16/9"場景長寬比(CSS aspect-ratio)
tiltnumber0場景隨游標的最大傾斜角度(度),上限 3,0 為關閉
childrenReactNode—疊在最上層的文字區,螢幕閱讀器正常讀取
containerRefObject<HTMLElement>—巢狀捲動容器的 ref;省略則以視窗為捲動容器
classNamestring—透傳到最外層容器

PaperLayer

欄位型別預設值說明
idstring—層的唯一識別
colorstring依層序取暖色紙紙張顏色(#f5efe6、#e9dfcf、#d9c9b0、#c2ab8a、#a88d68)
tornEdge"top" | "bottom" | "both""top"撕哪一邊
depthnumber依層序 0.2 → 1景深係數,越大位移越多
heightstring由後往前遞減紙片佔場景高度的百分比字串,如 "45%"
contentReactNode—紙片上的內容(自畫 SVG、文字),會一起被撕邊裁切

細節

  • 撕邊是 clip-path: polygon(...):以 seed 與層序跑確定性亂數,沿邊產生 24 到 48 個點,疊加低頻起伏與高頻小抖動;不用 Math.random,所以 SSR 與 client 形狀一致。
  • 陰影用兩段 drop-shadow,放在外層、clip-path 放在內層,陰影才會沿著撕邊形狀投影。可用 CSS 變數 --wb-paper-layers-shadow 覆寫整串陰影。
  • 捲動視差以 useScroll 追蹤場景本身:場景位於視窗中央時各層歸零,往下捲時近景往上走得比遠景快。
  • 游標視差以場景中心為原點,經 spring 平滑;游標離開時依 --wb-paper-layers-ease-duration(預設 600ms)緩緩回到中心。
  • 每張紙片在左右與下方都有留白延伸,位移再大也不會露出紙片邊緣。

可及性

  • 所有紙片層為裝飾,整組設定 aria-hidden;children 的標題與文字不受影響,正常被螢幕閱讀器讀取
  • 觸控裝置(無 hover、粗指標)自動停用游標視差,只保留捲動視差
  • 使用者系統開啟「減少動態效果」時,所有紙片固定不動,保留紙質、撕邊與陰影外觀