Hero Condense Header
捲動時英雄區的標題、頭像與 meta 以共享元素 FLIP 逐一遷移收攏進吸頂頁首,向上捲回再依序展開歸位。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
240
56
0.5
<HeroCondenseHeader />
安裝
npx shadcn@latest add https://webberui.com/r/hero-condense-header.json安裝依賴後,從 registry JSON(/r/hero-condense-header.json 的 files[0].content)複製 hero-condense-header.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
items 陣列裡的每個項目都是「同一個」在英雄區與吸頂列之間遷移的共享節點。heroClassName 定位它在英雄區的錨點(決定展開時的位置與尺寸),headerClassName 決定它收攏後在吸頂列的排版:
import {
HeroCondenseHeader,
type HeroCondenseItem,
} from "@/components/ui/hero-condense-header";
const items: HeroCondenseItem[] = [
{
id: "avatar",
content: <img src="/me.jpg" alt="Aria" className="h-full w-full rounded-full" />,
heroClassName: "inset-x-0 mx-auto top-9 h-16 w-16",
headerClassName: "order-1 h-8 w-8 shrink-0",
},
{
id: "title",
content: <span className="whitespace-nowrap text-sm font-semibold">Aria Nakamura</span>,
heroClassName: "inset-x-0 mx-auto top-[104px] h-7 w-56",
headerClassName: "order-2",
},
{
id: "meta",
content: <span className="whitespace-nowrap text-xs text-neutral-500">Product Designer</span>,
heroClassName: "inset-x-0 mx-auto top-[136px] h-5 w-64",
headerClassName: "order-3 ml-auto",
},
];
<HeroCondenseHeader items={items} heroHeight={240} headerHeight={56}>
<YourPageContent />
</HeroCondenseHeader>捲動容器可以是頁面本身(預設以視窗為捲動容器),也可以是任何 overflow-y: auto 的區塊——後者把該容器的 ref 傳入 container 即可(如上方示範)。
陣列順序即收攏先後:第一個項目最先收攏、最後展開;視覺上的列內排列則以 order-* 工具類獨立控制。
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
items | HeroCondenseItem[] | — | 依序遷移的共享元素;陣列順序即收攏先後 |
heroHeight | number | 240 | 英雄區總高度(px) |
headerHeight | number | 56 | 吸頂頁首列高度(px) |
condenseSpan | number | 0.5 | 單一項目收攏所佔的進度比例(0.05–1),越小交錯越明顯 |
container | React.RefObject<HTMLElement | null> | — | 捲動容器 ref;巢狀 overflow 容器需傳入,預設為視窗 |
heroClassName | string | — | 英雄層樣式(背景、圓角等) |
barClassName | string | — | 吸頂列容器樣式 |
children | React.ReactNode | — | 頁首下方的頁面內容 |
className | string | — | 附加到最外層容器的 class |
HeroCondenseItem
| 欄位 | 型別 | 說明 |
|---|---|---|
id | string | 唯一識別碼,用於配對英雄錨點與吸頂插槽 |
content | React.ReactNode | 共享元素內容(同一節點在兩端之間遷移) |
heroClassName | string | 英雄錨點定位(絕對定位);高度決定展開倍率、中心決定落點 |
headerClassName | string | 吸頂插槽排版;可用 order-* 調整列內順序 |
細節
- 展開倍率=
錨點高度 / 插槽高度,共享節點以其收攏(吸頂列)尺寸為基準,透過 transform 縮放至英雄尺寸——因此文字顏色不會隨遷移改變,請為英雄層挑選與吸頂列相容的底色 - 兩端幾何以
offsetParent鏈量測(transform 前的版面座標),不受捲動與 sticky 位移影響;定位錨點時請用left/top/inset/mx-auto等版面屬性,避免 transform 類工具(如-translate-x-1/2)以免量測失準 - 遷移全程只用
transform驅動、不觸發版面重排,並在尺寸或視窗變動時以ResizeObserver重新量測 - 每個項目沿自己的進度視窗(
condenseSpan寬、彼此以 stagger 錯開)補間,因此收攏/展開會逐一發生;condenseSpan越小、交錯越明顯
可及性
- 共享文字(姓名、職稱)只渲染一次且始終在 DOM 中,輔助科技可正常朗讀;英雄層的定位錨點為空且標記
aria-hidden - 使用者系統開啟「減少動態效果」時,直接渲染靜態的吸頂頁首(收攏態),不播放遷移動畫、也不渲染英雄區,仍是一個可用的頁首
- 吸頂列使用語意化的
<header>元素,形成頁面的 banner 地標