版面構圖
紙片分層場景
3 到 5 層撕邊紙片疊成的場景,隨捲動或游標做分層視差,每層有柔和紙張陰影與不規則撕邊,適合故事型首頁與編輯排版。
把 3 到 5 張撕邊紙片由後到前疊成一個場景:每張紙片有自己的顏色、以 seed 確定性產生的不規則撕邊、沿撕邊形狀投下的柔和紙張陰影,以及可選的紙纖維紋理。捲動頁面或移動游標時,越前面的紙片位移越多,形成剪紙繪本般的分層視差。每層可放自畫 SVG 或文字,最上層的 children 是正常可讀的標題區,適合故事型首頁與編輯排版。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add paper-layers-scenePlayground
即時調整 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 | 型別 | 預設值 | 說明 |
|---|---|---|---|
layers | PaperLayer[] | 四層預設暖色紙 | 由後到前疊放的紙片層,建議 3 到 5 層 |
mode | "scroll" | "pointer" | "both" | "both" | 視差驅動來源;觸控裝置上 pointer 停用,只留 scroll |
intensity | number | 18 | 游標視差強度(px),depth = 1 的層在游標移到邊緣時的最大位移 |
range | number | 120 | 捲動視差距離(px),depth = 1 的層在整段捲動過程中的總位移 |
stiffness | number | 120 | 游標視差 spring 剛性,越大跟隨越即時 |
damping | number | 20 | 游標視差 spring 阻尼,越小回位餘晃越明顯 |
seed | number | 3 | 撕邊亂數種子,同一個 seed 永遠產生同樣的撕邊 |
grain | boolean | true | 是否疊上紙纖維紋理(multiply 6%) |
aspectRatio | string | "16/9" | 場景長寬比(CSS aspect-ratio) |
tilt | number | 0 | 場景隨游標的最大傾斜角度(度),上限 3,0 為關閉 |
children | ReactNode | — | 疊在最上層的文字區,螢幕閱讀器正常讀取 |
container | RefObject<HTMLElement> | — | 巢狀捲動容器的 ref;省略則以視窗為捲動容器 |
className | string | — | 透傳到最外層容器 |
PaperLayer
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 層的唯一識別 |
color | string | 依層序取暖色紙 | 紙張顏色(#f5efe6、#e9dfcf、#d9c9b0、#c2ab8a、#a88d68) |
tornEdge | "top" | "bottom" | "both" | "top" | 撕哪一邊 |
depth | number | 依層序 0.2 → 1 | 景深係數,越大位移越多 |
height | string | 由後往前遞減 | 紙片佔場景高度的百分比字串,如 "45%" |
content | ReactNode | — | 紙片上的內容(自畫 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、粗指標)自動停用游標視差,只保留捲動視差
- 使用者系統開啟「減少動態效果」時,所有紙片固定不動,保留紙質、撕邊與陰影外觀