頁面區塊 Sections
墨色山脊主視覺
層疊的墨色山脊曲線由程式產生並逐層描繪,標題文字先描邊再填色,捲動時山脊分層視差。
首頁主視覺區塊:上半部是小標、標題、說明與兩顆 CTA,下半部是一整幅由程式產生的墨色山脊。山脊由遠到近逐層描出,遠層淺、近層深,最近一層帶一條強調色細線;每層描完後下方淡淡填上同色。標題先以描邊字出現,第一條山脊描完時由下往上填滿實色。捲動頁面時,近層上移較多、遠層較少,形成分層視差。換一個 seed 就是另一座山。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add ink-ridgeline-heroPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
7
5
1400
編輯中的呼叫預設屬性
<InkRidgelineHero/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/ink-ridgeline-hero.json或在 components.json 設定 registries 後,改用 @webberui/ink-ridgeline-hero 安裝。
使用
import { InkRidgelineHero } from "@/components/ui/ink-ridgeline-hero";
<InkRidgelineHero
eyebrow="嵐線戶外 · 秋季步道指南"
title="把週末留給山的稜線"
subtitle="一百二十條步道的海拔、坡度與補水點整理成一張路線卡。"
seed={7}
layers={5}
primaryAction={{ label: "找附近的步道", href: "/trails" }}
secondaryAction={{ label: "看路線卡範例", href: "#routes" }}
/>放在巢狀捲動容器內
預設追蹤的是視窗的捲動。若元件放在固定高度的 overflow-y-auto 容器內,請把該容器的 ref 傳給 container。山脊的視差位移跟著主視覺在容器內的捲動進度走。
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
<InkRidgelineHero container={scrollerRef} />
</div>以整個視窗為捲動容器時可省略 container,行為與原本相同。
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
title | ReactNode | — | 主標題(必填);描邊效果只是視覺,文字始終是可朗讀的真文字 |
eyebrow | ReactNode | — | 標題上方的小標 |
subtitle | ReactNode | — | 標題下方的副標 |
primaryAction | InkRidgelineHeroAction | — | 主要 CTA(背景為強調色) |
secondaryAction | InkRidgelineHeroAction | — | 次要 CTA(外框樣式) |
as | "h1" | "h2" | "h1" | 標題層級 |
minHeight | number | 560 | 區塊最小高度(px) |
seed | number | 7 | 山脊形狀的決定性種子;同一個 seed 永遠畫出同一組山 |
layers | number | 5 | 山脊層數,由遠到近,限制在 3–7 |
align | "left" | "center" | "left" | 文字對齊 |
strokeTitle | boolean | true | 標題先以描邊出現、第一條山脊描完時由下往上填滿實色 |
draw | number | — | 每層山脊的描繪時長(ms),寫入 --wb-ink-ridgeline-hero-draw;未提供時沿用 CSS 變數(預設 1400ms) |
duration | number | — | 文字進場時長(ms),寫入 --wb-ink-ridgeline-hero-duration;未提供時沿用 CSS 變數(預設 600ms) |
container | RefObject<HTMLElement> | — | 巢狀捲動容器的 ref;省略則以視窗為捲動容器 |
className | string | — | 併入根 section 的 class |
InkRidgelineHeroAction
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 按鈕文字 |
href | string | — | 提供時渲染為連結 a,否則為 button |
onClick | (event: React.MouseEvent<HTMLElement>) => void | — | 點擊回呼 |
細節
- 山脊形狀:每層以
seed產生的 1D value noise(四個八度疊加)取 52 個點,再以 Catmull-Rom 轉成平滑的 cubic Bézier。整個過程是決定性的,伺服器與瀏覽器畫出同一座山,不會有 hydration 落差。 - 描繪:每條線以
pathLength正規化後用stroke-dashoffset從 1 走到 0,曲線cubic-bezier(0.65,0,0.35,1),層間錯開 180ms;描完後填色在 500ms 內淡入。 - 標題填色:用
-webkit-text-stroke畫出描邊,字面透明,再以background-clip: text搭配background-size由下往上填滿,時間點對齊第一條山脊描完。 - 捲動視差:以
useScroll追蹤區塊本身,近層上移到 -60px、遠層 -15px;填色往下延伸,上移時底部不會露出空隙。 - 可覆寫的 CSS 變數:
--wb-ink-ridgeline-hero-draw(描繪時長)、--wb-ink-ridgeline-hero-duration(文字進場時長)、--wb-ink-ridgeline-hero-accent(強調色,預設#0d9488,暗色#2dd4bf)。 - 高度由內容與
minHeight決定,元件本身不使用視窗高度單位;窄螢幕時山脊裁切左右而不壓扁線條。
可及性
- 根元素是
section,以aria-labelledby指向標題;標題層級由as決定。 - 山脊 SVG 標記
aria-hidden,螢幕閱讀器不會讀到裝飾。 - 標題的描邊與填色只是視覺樣式,文字始終是真文字,朗讀與選取都不受影響。
- CTA 是
a或type="button",有清楚的 focus-visible 外框。 - 系統開啟「減少動態效果」時,山脊直接以完整構圖呈現、不逐層描繪,標題直接是實色,文字進場改為 150ms 淡入,捲動視差固定在終態;此設定在首次繪製即以 CSS 媒體查詢生效。