WebberUI

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.jsonfiles[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 傳給 GlyphPortalLayoutcontainer

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型別預設值說明
childrenReact.ReactNode放入 GlyphPortal 與任意文字內容
intensitynumber56視差行程強度(px),影像於字身內位移的最大幅度
fontFamilystring粗體系統字體堆疊遮罩字體堆疊(於 CSS mask 內以系統字體算繪)
fontWeightnumber | string900遮罩字重
columnsnumber6網格欄數
containerRefObject<HTMLElement | null>巢狀捲動容器 ref;預設以視窗為捲動容器
classNamestring附加樣式

GlyphPortal Props

Prop型別預設值說明
glyphstring作為視窗遮罩的字符(通常為單一字母/數字/漢字)
srcstring影像或影片來源 URL
media"image" | "video"依副檔名自動判斷媒體類型
posterstring影片海報圖(mediavideo 時)
altstring無障礙替代文字;未提供時此視窗視為裝飾性
mode"fill" | "knockout""fill"fill 影像填入字身;knockout 字形自影像鏤空
depthnumber1視差深度倍率,用來製造層次
direction1 | -11視差方向
aspectstring"3 / 4"單格長寬比(與遮罩比例一致時字形不變形)
spannumber網格欄位跨距
classNamestring附加樣式
childrenReact.ReactNode疊在字形視窗上、不攔截指標的內容

GlyphProse Props

Prop型別預設值說明
childrenReact.ReactNode繞排於字形骨架之間的小字內容
spannumber網格欄位跨距
classNamestring附加樣式

細節

  • 遮罩透過 CSS mask-image 帶入一段內嵌 SVG 的 data-URI,字形以系統字體算繪,因此無需在專案中設定任何字體檔或全域 CSS。
  • 因遮罩內的 SVG 讀不到頁面的 @font-facefontFamily 請沿用預設或改指定普遍可用的重量級字體。
  • 遮罩以 mask-size: 100% 100% 貼合單格;當 aspect 與遮罩內建比例(3 / 4)一致時字形不變形,刻意改變比例可製造壓縮/拉長的字形效果。
  • 每個 GlyphPortal 以自身位置計算捲動進度,搭配 depthdirection 讓各字視差不同步,形成層次;影像以 overscan 溢出單格,任何位移下都不會露出邊界。

可及性

  • 使用者系統開啟「減少動態效果」時,停用視差位移與影片自動播放,字形視窗維持靜態版面。
  • 提供 alt 的視窗以 role="img"aria-label 對輔助科技朗讀;未提供 alt 時整個視窗標記為 aria-hidden,內部影像亦對輔助科技隱藏。
  • 疊加內容(children)以 pointer-events-none 呈現,不攔截底層互動。

On this page