Glyph Portal Layout
以巨型字母作為遮罩視窗的排版骨架,字身內嵌獨立影像/影片並於捲動時視差移動,周邊小字繞排其間。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
56
6
<GlyphPortalLayout />
安裝
npx shadcn@latest add https://webberui.com/r/glyph-portal-layout.json或在 components.json 設定 registries 後,改用 @webberui/glyph-portal-layout 安裝。
安裝依賴後,從 registry JSON(/r/glyph-portal-layout.json 的 files[0].content)複製 glyph-portal-layout.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
GlyphPortalLayout 提供共用的捲動進度與遮罩設定,內部放入任意數量的 GlyphPortal(字形視窗)與 GlyphProse(繞排小字)。每個 GlyphPortal 以一個巨型字母作為遮罩,字身內嵌的影像會隨捲動於字身內視差移動。
import {
GlyphPortal,
GlyphPortalLayout,
GlyphProse,
} from "@/components/ui/glyph-portal-layout";
<GlyphPortalLayout columns={2} intensity={64}>
<GlyphProse span={2}>巨型字母即是版面骨架。</GlyphProse>
<GlyphPortal glyph="T" src="/media/dawn.jpg" alt="曙光" depth={1.4} />
<GlyphPortal glyph="Y" src="/media/flame.mp4" alt="火焰" depth={0.8} />
<GlyphPortal glyph="P" src="/media/moss.jpg" alt="苔蘚" depth={1.2} />
<GlyphPortal glyph="E" src="/media/night.jpg" alt="夜色" depth={0.9} />
<GlyphProse span={2}>周邊小字繞排其間,構成以字形為主角的編排。</GlyphProse>
</GlyphPortalLayout>;若捲動發生在巢狀的 overflow 容器內,將該容器的 ref 傳給 GlyphPortalLayout 的 container:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
<GlyphPortalLayout container={scrollerRef}>{/* … */}</GlyphPortalLayout>
</div>;src 為 .mp4/.webm 等副檔名時會自動以 <video> 呈現,也可用 media="video" 明確指定。
GlyphPortalLayout Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 放入 GlyphPortal 與任意文字內容 |
intensity | number | 56 | 視差行程強度(px),影像於字身內位移的最大幅度 |
fontFamily | string | 粗體系統字體堆疊 | 遮罩字體堆疊(於 CSS mask 內以系統字體算繪) |
fontWeight | number | string | 900 | 遮罩字重 |
columns | number | 6 | 網格欄數 |
container | RefObject<HTMLElement | null> | — | 巢狀捲動容器 ref;預設以視窗為捲動容器 |
className | string | — | 附加樣式 |
GlyphPortal Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
glyph | string | — | 作為視窗遮罩的字符(通常為單一字母/數字/漢字) |
src | string | — | 影像或影片來源 URL |
media | "image" | "video" | 依副檔名自動判斷 | 媒體類型 |
poster | string | — | 影片海報圖(media 為 video 時) |
alt | string | — | 無障礙替代文字;未提供時此視窗視為裝飾性 |
mode | "fill" | "knockout" | "fill" | fill 影像填入字身;knockout 字形自影像鏤空 |
depth | number | 1 | 視差深度倍率,用來製造層次 |
direction | 1 | -1 | 1 | 視差方向 |
aspect | string | "3 / 4" | 單格長寬比(與遮罩比例一致時字形不變形) |
span | number | — | 網格欄位跨距 |
className | string | — | 附加樣式 |
children | React.ReactNode | — | 疊在字形視窗上、不攔截指標的內容 |
GlyphProse Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 繞排於字形骨架之間的小字內容 |
span | number | — | 網格欄位跨距 |
className | string | — | 附加樣式 |
細節
- 遮罩透過 CSS
mask-image帶入一段內嵌 SVG 的 data-URI,字形以系統字體算繪,因此無需在專案中設定任何字體檔或全域 CSS。 - 因遮罩內的 SVG 讀不到頁面的
@font-face,fontFamily請沿用預設或改指定普遍可用的重量級字體。 - 遮罩以
mask-size: 100% 100%貼合單格;當aspect與遮罩內建比例(3 / 4)一致時字形不變形,刻意改變比例可製造壓縮/拉長的字形效果。 - 每個
GlyphPortal以自身位置計算捲動進度,搭配depth/direction讓各字視差不同步,形成層次;影像以 overscan 溢出單格,任何位移下都不會露出邊界。
可及性
- 使用者系統開啟「減少動態效果」時,停用視差位移與影片自動播放,字形視窗維持靜態版面。
- 提供
alt的視窗以role="img"與aria-label對輔助科技朗讀;未提供alt時整個視窗標記為aria-hidden,內部影像亦對輔助科技隱藏。 - 疊加內容(
children)以pointer-events-none呈現,不攔截底層互動。