頁面區塊 Sections

城市天際線捲動主視覺

由捲動驅動的分段城市天際線 React 主視覺元件:往下捲時天色由黃昏轉入夜,建築一段段點亮窗燈,段落標題隨之切換,最後一段月亮升起。

一段捲動敘事型的首頁主視覺。外層 section 撐出 scrollLength 的捲動距離,內層舞台以 sticky 固定在頂端;捲動進度經彈簧平滑後驅動整個場景——天空漸層從黃昏的杏桃色、經過藍調時刻、沉入深夜,底部的天際線剪影同步由淺轉深。建築由 seed 決定性產生並分成與 stages 等量的群,進入哪一段,那一群建築的窗燈就以固定的亂序逐格亮起,段落文字也跟著淡出淡入切換;最後一段月亮從地平線升起。

把這個效果裝進你的專案

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

npx webberui@latest add skyline-scroll-hero

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

Playground

即時調整 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型別預設值說明
titleReactNode—主標題(必填),整段捲動期間固定不變
eyebrowReactNode—標題上方的小標
subtitleReactNode—主標題下方的副標題
as"h1" | "h2""h1"標題層級,頁面已有 h1 時改用 h2
primaryActionSkylineScrollHeroAction—主要 CTA,底色為強調色
secondaryActionSkylineScrollHeroAction—次要 CTA,外框樣式
stagesSkylineScrollHeroStage[][]每段一組文字;長度決定天際線分成幾段(空陣列時分三段、不顯示段落文字)
seednumber3建築生成的種子,同一個種子永遠畫出同一座城市
scrollLengthnumber1800外層 section 的總捲動高度(px),越長每段停留越久
stageHeightnumber600sticky 舞台的高度(px)
minHeightnumber560減少動態效果時(一般高度 hero)的最小高度(px)
containerRefObject<HTMLElement | null>—捲動容器;省略時跟隨視窗捲動
durationnumber—段落文字切換時長(ms),寫入 --wb-skyline-scroll-hero-switch;省略時為 300ms
enterDurationnumber—標題區進場時長(ms),寫入 --wb-skyline-scroll-hero-duration;省略時為 600ms
stiffnessnumber—進度彈簧剛度,寫入 --wb-skyline-scroll-hero-stiffness;省略時為 100(damping 固定 30)
onStageChange(index: number) => void—當前段落改變時回呼,參數為從 0 起算的段落索引
classNamestring—併入根 section 的 class

SkylineScrollHeroStage

欄位型別預設值說明
titlestring—這一段的標題
subtitlestring—這一段的補充說明

SkylineScrollHeroAction

欄位型別預設值說明
labelstring—按鈕文字
hrefstring—連結網址;有給時渲染為 <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 淡入