文字動畫

液態折射揭露

以 SVG 位移濾鏡讓內容像隔著液滴折射晃動,點擊或進入視口時折射歸零、液面破裂,清楚揭露標誌或標題。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

把標誌、標題或任何內容包進一顆緩慢變形的液珠裡:內容隔著液面折射晃動,紋理頻率持續「呼吸」;觸發時位移先衝到極限、再以彈簧歸零,液珠外形攤平並向外噴出一圈小液滴,內容清楚現身。適合品牌開場、新版發佈標題與 hero 區塊的揭露瞬間。折射用的是內嵌的 SVG 濾鏡(feTurbulence+feDisplacementMap),不需要 canvas 或 WebGL。

把這個效果裝進你的專案

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

npx webberui@latest add "https://webberui.com/r/liquid-reveal.json?t=<安裝 token>"

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

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

40
0.012
8
編輯中的呼叫預設屬性
<LiquidReveal/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add "https://webberui.com/r/liquid-reveal.json?t=<安裝 token>"

或在 components.json 設定 registries 後,改用 @webberui/liquid-reveal 安裝。

使用

import * as React from "react";
import {
  LiquidReveal,
  type LiquidRevealHandle,
} from "@/components/ui/liquid-reveal";

// 點擊揭露:容器本身是按鈕
<LiquidReveal trigger="click" contentLabel="水禾 品牌字標" tint="rgba(56,189,248,0.16)">
  <Logo />
</LiquidReveal>;

// 進入視口自動揭露,並以 ref 重播
function Headline() {
  const ref = React.useRef<LiquidRevealHandle>(null);
  return (
    <>
      <LiquidReveal ref={ref} trigger="inView" droplets={10} grain>
        <h2 className="text-4xl font-bold">新版上線</h2>
      </LiquidReveal>
      <button type="button" onClick={() => ref.current?.reset()}>
        重播
      </button>
    </>
  );
}

Props

Prop型別預設值說明
childrenReact.ReactNode—被液滴包住、最後要揭露的內容(文字、SVG 標誌、圖示組合皆可)
revealedboolean—受控的揭露狀態;未提供時由元件內部管理
defaultRevealedbooleanfalse非受控模式的初始揭露狀態
onRevealedChange(revealed: boolean) => void—揭露狀態改變時回呼
trigger"click" | "inView" | "manual""inView"click 讓容器成為按鈕;inView 有 60% 進入視口時自動破裂;manual 只靠 revealed 或 ref
restScalenumber40待機時的位移強度(feDisplacementMap 的 scale);越大折射越扭曲
frequencynumber0.012折射紋理的基準頻率(feTurbulence 的 baseFrequency);越大波紋越細碎
dropletsnumber8破裂時向外噴出的小液滴數量(0 為不噴)
tintstring—液滴染色(任何 CSS 顏色);寫入 --wb-liquid-reveal-tint,未設定時透明
grainbooleanfalse在液面疊一層細噪點,增添擬物質感
revealLabelstring"揭露內容"trigger="click" 時,揭露前按鈕的無障礙名稱
contentLabelstring—揭露後的無障礙名稱(內容描述);未提供時由 children 的文字命名
refReact.Ref<LiquidRevealHandle>—取得 reveal()/reset() 方法
classNamestring—透傳到最外層容器

LiquidRevealHandle

欄位型別預設值說明
reveal() => void—立即揭露(等同觸發一次破裂)
reset() => void—回到液滴態,重新開始折射晃動

另外具名匯出 LiquidRevealTrigger、LiquidRevealHandle 與 LiquidRevealProps 型別。

CSS 變數

欄位型別預設值說明
--wb-liquid-reveal-duration<time>700ms揭露時液珠外形攤平、染色與高光淡出的時間
--wb-liquid-reveal-tint<color>transparent液滴底色;tint prop 會寫入這個變數
--wb-liquid-reveal-wobble<time>6s液珠外形變形一輪的週期

細節

  • 折射:容器內放一個 0×0 的內嵌 SVG,定義 feTurbulence(fractalNoise、2 個 octave、固定 seed)接 feDisplacementMap;children 所在的層以 filter: url(#id) 套用,id 由 useId 產生,同頁多個實例互不干擾
  • 不逐幀重繪:位移強度與紋理頻率都是 motion value,動畫中直接把數值寫進 SVG 屬性,不觸發 React 重新渲染
  • 待機呼吸:baseFrequency 在 frequency 的 10/12 到 16/12 之間以 4 秒來回;元件離開視口就停止,省下濾鏡重算
  • 破裂三段:位移先在 120ms 內衝到 restScale 的 1.6 倍,再以彈簧(stiffness 180、damping 18)降到 0;同時液珠放大到 1.08 再回彈、外形攤平,並以確定性角度噴出小液滴(飛 24–60px、500ms 淡出)。動畫結束後濾鏡整個移除,內容回到原生清晰度
  • inView 只在「進入」時觸發:呼叫 reset() 時若仍在視口內,不會立刻又破裂,要捲出再捲回才會重播
  • Safari 降級:Safari 對 HTML 元素套 SVG 位移濾鏡的支援不穩,偵測到時改用 CSS blur(6px) 漸變到 0,節奏相同

可及性

  • 濾鏡純屬視覺:children 始終留在 DOM 中,文字可被選取、搜尋與朗讀
  • trigger="click" 時容器是 type="button" 的按鈕,可用 Tab 聚焦、Enter/空白鍵觸發,並有 focus-visible 外框;揭露前的無障礙名稱為 revealLabel(預設「揭露內容」),揭露後改為 contentLabel,未提供時由 children 的文字命名
  • SVG 濾鏡定義、高光、噪點與噴出的小液滴都標記 aria-hidden
  • 使用者系統開啟「減少動態效果」時,直接顯示 children:不套濾鏡、不變形、不噴液滴,也沒有呼吸動畫