媒體

頻閃圖牆

全幅圖片極快連續翻頁、中央內容固定不動的頻閃效果 React 元件,播放結束停在最後一張;可由進入視口、掛載或 ref.play() 觸發,減少動態效果時改為慢速交叉淡接。

適合影展、發表會、品牌首頁開場的頻閃主視覺。所有圖層一次掛載、疊在同一位置,以 opacity 硬切換,每 intervalMs(預設 80ms)翻一張;中央的 children(字標、標語)始終不動。跑完 cycles 輪(或 durationMs 時間)後停在最後一張並呼叫 onEnd。圖層可以是 { src, alt } 圖片,也可以是任意 ReactNode——例如純 CSS 漸層的 div。

把這個效果裝進你的專案

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

npx webberui@latest add image-strobe

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

Playground

即時調整 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型別預設值說明
imagesImageStrobeItem[]—圖層清單:{ src, alt } 或 ReactNode,依序翻頁
intervalMsnumber80每張停留的毫秒數(亦鏡像為 --wb-is-interval 變數,以 prop 為準)
cyclesnumber3播放幾輪 images;有設定 durationMs 時以 durationMs 為準
durationMsnumber—總播放長度(毫秒),優先於 cycles
endIndexnumber最後一張播放結束後停留的圖層索引
trigger"mount" | "inView" | "manual""inView"掛載即播、進入視口一半時播一次,或只由 ref.play() 啟動
flashbooleanfalse每次切換疊一層 1 幀的淡白閃光
scrimbooleanfalse在圖層與中央內容之間疊一層暗角漸層(可用 --wb-is-scrim 覆寫)
childrenReactNode—釘在中央、不隨翻頁變化的內容
aspectstring"16/9"容器寬高比(CSS aspect-ratio)
onEnd() => void—播放結束、停在最後一張時呼叫
refRef<ImageStrobeHandle>—命令式控制,提供 play() 從頭(重新)播放
classNamestring—透傳到最外層容器

ImageStrobeImage

欄位型別預設值說明
srcstring—圖片網址
altstring—替代文字;只有最後停留的那一張會以 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 秒的交叉淡接慢播一輪,結束後同樣停在最後一張。