文字動畫

Scroll Text Highlight

文字隨滾動進度逐字(或逐詞)由淡灰轉為前景實色的閱讀高亮。

把這個效果裝進你的專案

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

npx webberui@latest add scroll-text-highlight

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

Scroll Text Highlight 是用 React 與 Motion 的 useScroll 做的捲動文字高亮(scroll reveal text、捲動逐字點亮)元件:段落捲過畫面時,文字依序從淡灰轉為實色,可以逐字或逐詞進行,也支援巢狀捲動容器。

Playground

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

編輯中的呼叫預設屬性
<ScrollTextHighlight/>

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

適用情境

  • 品牌頁或「關於我們」的理念宣言段落,讓讀者跟著捲動節奏讀完
  • 產品發表頁在兩段大圖之間的過場文字
  • 長篇故事型頁面(scrollytelling)的重點引言
  • 簡報式的單頁介紹,一個畫面只放一句話

安裝

npx webberui@latest add https://webberui.com/r/scroll-text-highlight.json

或在 components.json 設定 registries 後,改用 @webberui/scroll-text-highlight 安裝。

使用

放在巢狀捲動容器內時,把容器的 ref 傳給 container:

import * as React from "react";
import { ScrollTextHighlight } from "@/components/ui/scroll-text-highlight";

export function Example() {
  const scrollerRef = React.useRef<HTMLDivElement>(null);

  return (
    <div ref={scrollerRef} className="h-[300px] overflow-y-auto">
      <div className="py-40">
        <ScrollTextHighlight
          container={scrollerRef}
          text="隨著滾動逐字點亮的文字。"
          className="text-xl font-semibold"
        />
      </div>
    </div>
  );
}

以整個視窗為捲動容器時,可省略 container:

<ScrollTextHighlight
  by="word"
  text="Scroll to reveal."
  className="text-4xl font-bold"
/>

範例

品牌理念區塊

每個 ScrollTextHighlight 各自追蹤自己的捲動進度,多段文字可以依序點亮。上下留白讓段落有足夠的捲動距離。

import { ScrollTextHighlight } from "@/components/ui/scroll-text-highlight";

const paragraphs = [
  "我們相信好的工具應該安靜地待在背景。",
  "所以每個元件都附上完整的程式碼,你可以讀、可以改,也可以整個拿走。",
];

export function Manifesto() {
  return (
    <section className="mx-auto max-w-3xl space-y-24 py-[40vh]">
      {paragraphs.map((p) => (
        <ScrollTextHighlight
          key={p}
          text={p}
          className="text-3xl font-semibold leading-relaxed md:text-5xl"
        />
      ))}
    </section>
  );
}

指定文字顏色

未亮起的部分是同一個顏色、透明度 0.2,所以只要用 className 設定字色,深淺模式各自調整即可。

<ScrollTextHighlight
  text="三分鐘完成部署,不需要設定伺服器。"
  className="text-4xl font-bold text-indigo-600 dark:text-indigo-300"
/>

英文段落逐詞高亮

by="word" 以空白切分,適合英文等以空白分詞的語言,節奏比逐字慢一些。

<ScrollTextHighlight
  by="word"
  text="Ship faster with components you fully own."
  className="text-5xl font-semibold tracking-tight"
/>

Props

Prop型別預設值說明
textstring—要隨滾動高亮的文字
by"char" | "word""char"高亮的最小單位
containerRefObject<HTMLElement>—巢狀捲動容器的 ref;省略則以視窗為捲動容器
classNamestring—附加樣式(建議在此設定字級與字色)

細節

  • 以 useScroll({ target, container, offset: ["start end", "end start"] }) 取得目標文字在容器內從進入底部到離開頂部的捲動進度 scrollYProgress
  • 每個字(或詞)依索引分配到 [start, end] 的子區間,透過 useTransform 把進度映射成 opacity,逐一由淡灰轉為前景實色
  • 逐字模式以字素(grapheme)切割,emoji 與組合字不會被拆壞
  • 文字沿用 currentColor(前景色),淡出時自然呈現淺灰;請透過 className 指定字級與字色

可及性

  • 完整文字以 sr-only 呈現供輔助科技朗讀,逐字動畫層標記 aria-hidden,不會被重複朗讀
  • 使用者系統開啟「減少動態效果」時,直接渲染全部前景實色的靜態文字

常見問題

中文可以用 by="word" 嗎?

不建議。逐詞模式是用空白切分,中文句子中間沒有空白,整句會被當成一個單位一次亮起。中文請維持預設的 by="char"。

可以在 Next.js App Router 使用嗎?

可以。原始碼已經有 "use client",在 Server Component 頁面直接 import 即可。「減少動態效果」的靜態版在掛載後才切換,首次渲染與伺服器輸出一致。

高亮從什麼時候開始、什麼時候結束?

捲動進度的範圍是 offset: ["start end", "end start"]:段落頂端碰到可視區底部時開始,段落底端離開可視區頂部時結束,每個字平均分配其中一段,所以最後幾個字會在段落接近畫面頂端時才亮起。

text 可以放粗體或連結嗎?

不行。text 型別是 string,元件會把它切成字或詞再個別上透明度;需要混排樣式時,可以拆成多個元件,或在外層包裝。

螢幕閱讀器會重複讀嗎?

不會。完整文字放在 sr-only 的 span 裡,逐字動畫層標記 aria-hidden。元件執行時只 import motion。