頁面區塊 Sections
城市天際線捲動主視覺
由捲動驅動的分段城市天際線 React 主視覺元件:往下捲時天色由黃昏轉入夜,建築一段段點亮窗燈,段落標題隨之切換,最後一段月亮升起。
一段捲動敘事型的首頁主視覺。外層 section 撐出 scrollLength 的捲動距離,內層舞台以 sticky 固定在頂端;捲動進度經彈簧平滑後驅動整個場景——天空漸層從黃昏的杏桃色、經過藍調時刻、沉入深夜,底部的天際線剪影同步由淺轉深。建築由 seed 決定性產生並分成與 stages 等量的群,進入哪一段,那一群建築的窗燈就以固定的亂序逐格亮起,段落文字也跟著淡出淡入切換;最後一段月亮從地平線升起。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add skyline-scroll-heroPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
3
1800
100
300
編輯中的呼叫預設屬性
<SkylineScrollHero/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/skyline-scroll-hero.json或在 components.json 設定 registries 後,改用 @webberui/skyline-scroll-hero 安裝。
使用
import { SkylineScrollHero } from "@/components/ui/skyline-scroll-hero";
<SkylineScrollHero
eyebrow="港灣夜行 · 城市散步路線"
title="一座城,三段夜色。"
stages={[
{ title: "六點,西區先亮起來", subtitle: "老街與巷口小店是路線的起點。" },
{ title: "七點半,河岸的辦公樓下班了" },
{ title: "九點,東區的塔樓與月亮同框" },
]}
primaryAction={{ label: "預約今晚的路線", href: "/booking" }}
secondaryAction={{ label: "看路線地圖", href: "/map" }}
/>元件放在自訂的捲動容器(例如固定高度、overflow-y-auto 的區塊)裡時,把容器的 ref 傳給 container,捲動進度才會跟著那個容器計算:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="relative h-[420px] overflow-y-auto">
<SkylineScrollHero container={scrollerRef} stageHeight={420} title="一座城,三段夜色。" />
</div>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
title | ReactNode | — | 主標題(必填),整段捲動期間固定不變 |
eyebrow | ReactNode | — | 標題上方的小標 |
subtitle | ReactNode | — | 主標題下方的副標題 |
as | "h1" | "h2" | "h1" | 標題層級,頁面已有 h1 時改用 h2 |
primaryAction | SkylineScrollHeroAction | — | 主要 CTA,底色為強調色 |
secondaryAction | SkylineScrollHeroAction | — | 次要 CTA,外框樣式 |
stages | SkylineScrollHeroStage[] | [] | 每段一組文字;長度決定天際線分成幾段(空陣列時分三段、不顯示段落文字) |
seed | number | 3 | 建築生成的種子,同一個種子永遠畫出同一座城市 |
scrollLength | number | 1800 | 外層 section 的總捲動高度(px),越長每段停留越久 |
stageHeight | number | 600 | sticky 舞台的高度(px) |
minHeight | number | 560 | 減少動態效果時(一般高度 hero)的最小高度(px) |
container | RefObject<HTMLElement | null> | — | 捲動容器;省略時跟隨視窗捲動 |
duration | number | — | 段落文字切換時長(ms),寫入 --wb-skyline-scroll-hero-switch;省略時為 300ms |
enterDuration | number | — | 標題區進場時長(ms),寫入 --wb-skyline-scroll-hero-duration;省略時為 600ms |
stiffness | number | — | 進度彈簧剛度,寫入 --wb-skyline-scroll-hero-stiffness;省略時為 100(damping 固定 30) |
onStageChange | (index: number) => void | — | 當前段落改變時回呼,參數為從 0 起算的段落索引 |
className | string | — | 併入根 section 的 class |
SkylineScrollHeroStage
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
title | string | — | 這一段的標題 |
subtitle | string | — | 這一段的補充說明 |
SkylineScrollHeroAction
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 按鈕文字 |
href | string | — | 連結網址;有給時渲染為 <a>,否則為 type="button" |
onClick | () => void | — | 點擊回呼 |
細節
- 捲動進度用
useScroll的offset: ['start start', 'end end']計算:section 頂端碰到視窗頂端時為 0、底端碰到視窗底端時為 1,中間平均切成stages.length段。 - 建築以
seed的確定性亂數產生 24–36 棟(寬 30–90、高 80–320),屋頂有平頂、尖塔、階梯、天線四種;伺服器與瀏覽器畫出完全一樣的城市,不會有 hydration 落差。 - 每棟建築只在亮燈數變動時重繪,上千個窗格不會每一幀都重算;窗燈的點亮順序也由種子洗牌決定,看起來像住戶各自開燈。
- 根元素在捲動模式下使用
overflow-clip而非overflow-hidden:後者會讓 section 自成捲動容器,sticky 舞台就黏不住。 - 可覆寫的 CSS 變數:天空四個色站
--wb-skyline-scroll-hero-dusk(#f5c99b)、--wb-skyline-scroll-hero-twilight(#e8a0a0)、--wb-skyline-scroll-hero-blue(#4b5f8a)、--wb-skyline-scroll-hero-night(#0b1220);窗燈--wb-skyline-scroll-hero-window(#fde68a);剪影--wb-skyline-scroll-hero-building-from/-to;強調色--wb-skyline-scroll-hero-accent(亮色 #0d9488、暗色 #2dd4bf);節奏--wb-skyline-scroll-hero-duration、--wb-skyline-scroll-hero-switch、--wb-skyline-scroll-hero-stiffness、--wb-skyline-scroll-hero-ease。 - 元件不使用
vh/h-screen,高度完全由scrollLength與stageHeight(px)決定。
可及性
- 根元素是
<section aria-labelledby>,指向主標題;天際線、天空、月亮與右側進度點都是aria-hidden的裝飾 - 所有段落文字都以 sr-only 清單留在 DOM 裡(當前段標記
aria-current="step"),螢幕閱讀器不會因為捲動位置而漏讀;視覺上的切換動畫對輔助科技隱藏 - CTA 為
<a>或type="button",帶 focus-visible 外框 - 文字顏色隨天色切換深淺,黃昏時用深色字、入夜後轉白字,維持與背景的對比
- 使用者系統開啟「減少動態效果」時,不做 sticky 捲動敘事,改為一般高度 hero:直接呈現終態的夜景(窗燈全亮、月亮已升起)與第一段文字,標題區進場改為 150ms 淡入