媒體
頻閃圖牆
全幅圖片極快連續翻頁、中央內容固定不動的頻閃效果 React 元件,播放結束停在最後一張;可由進入視口、掛載或 ref.play() 觸發,減少動態效果時改為慢速交叉淡接。
適合影展、發表會、品牌首頁開場的頻閃主視覺。所有圖層一次掛載、疊在同一位置,以 opacity 硬切換,每 intervalMs(預設 80ms)翻一張;中央的 children(字標、標語)始終不動。跑完 cycles 輪(或 durationMs 時間)後停在最後一張並呼叫 onEnd。圖層可以是 { src, alt } 圖片,也可以是任意 ReactNode——例如純 CSS 漸層的 div。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add image-strobePlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
80
3
編輯中的呼叫預設屬性
<ImageStrobe/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/image-strobe.json或在 components.json 設定 registries 後,改用 @webberui/image-strobe 安裝。
使用
import * as React from "react";
import { ImageStrobe, type ImageStrobeHandle } from "@/components/ui/image-strobe";
const frames = [
{ src: "/festival/01.jpg" },
{ src: "/festival/02.jpg" },
{ src: "/festival/03.jpg", alt: "海報主視覺:夜色中的放映廳" },
];
export function Hero() {
const ref = React.useRef<ImageStrobeHandle>(null);
return (
<>
<ImageStrobe ref={ref} images={frames} intervalMs={80} cycles={3} scrim>
<h1 className="text-4xl font-semibold text-white">拾光影展 2026</h1>
</ImageStrobe>
<button type="button" onClick={() => ref.current?.play()}>
重播
</button>
</>
);
}Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
images | ImageStrobeItem[] | — | 圖層清單:{ src, alt } 或 ReactNode,依序翻頁 |
intervalMs | number | 80 | 每張停留的毫秒數(亦鏡像為 --wb-is-interval 變數,以 prop 為準) |
cycles | number | 3 | 播放幾輪 images;有設定 durationMs 時以 durationMs 為準 |
durationMs | number | — | 總播放長度(毫秒),優先於 cycles |
endIndex | number | 最後一張 | 播放結束後停留的圖層索引 |
trigger | "mount" | "inView" | "manual" | "inView" | 掛載即播、進入視口一半時播一次,或只由 ref.play() 啟動 |
flash | boolean | false | 每次切換疊一層 1 幀的淡白閃光 |
scrim | boolean | false | 在圖層與中央內容之間疊一層暗角漸層(可用 --wb-is-scrim 覆寫) |
children | ReactNode | — | 釘在中央、不隨翻頁變化的內容 |
aspect | string | "16/9" | 容器寬高比(CSS aspect-ratio) |
onEnd | () => void | — | 播放結束、停在最後一張時呼叫 |
ref | Ref<ImageStrobeHandle> | — | 命令式控制,提供 play() 從頭(重新)播放 |
className | string | — | 透傳到最外層容器 |
ImageStrobeImage
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
src | string | — | 圖片網址 |
alt | string | — | 替代文字;只有最後停留的那一張會以 sr-only 提供給螢幕閱讀器 |
ImageStrobeItem 是 ImageStrobeImage \| ReactNode。
ImageStrobeHandle
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
play | () => void | — | 從第一張開始(重新)播放 |
細節
- 全部圖層一次掛載並疊在同一位置(
absolute inset-0、object-cover),以 opacity 0/1 硬切換、不加 transition,避免每次切換重新解碼。 - 開始播放前先用
img.decode()預載全部圖片;載完之前停在第一張。 - 計時用
requestAnimationFrame累計時間,不用setInterval:分頁在背景時不會累積計時、回到前景也不會一口氣狂翻。 - 播放長度:有
durationMs就以它為準,否則跑cycles輪;結束後停在endIndex(預設最後一張)並呼叫onEnd。 - 可用 CSS 變數
--wb-is-scrim換掉暗角漸層、--wb-is-fade調整減少動態效果時的淡接時間(預設 1200ms)。 - 光敏警示:80ms 約等於每秒 12.5 次閃爍。請避免讓大面積、高對比的畫面頻閃(例如黑白交替、飽和紅色),盡量挑亮度相近的圖片,並控制總播放時間;元件不會自動調整相鄰圖片的亮度差。
可及性
- 圖層容器設定
aria-hidden="true":頻閃是純裝飾,不會被螢幕閱讀器逐張朗讀。 - 若最後停留的圖片有意義,傳入
alt即會以 sr-only 文字提供;中央的children照常可被讀取與操作。 trigger="inView"只觸發一次,捲動來回不會反覆閃爍;需要重播時由使用者主動操作(例如按鈕呼叫ref.play())。- 使用者系統開啟「減少動態效果」時不做頻閃:改為每張 1.2 秒的交叉淡接慢播一輪,結束後同樣停在最後一張。