版面構圖

捲動漸隱清單

上下邊緣漸隱高度隨剩餘可捲距離即時變化的 React 捲動清單元件:到頂不顯示上方漸層、到底不顯示下方漸層,可選自動捲動並在滑鼠移入、聚焦或觸控時暫停。

長清單放進固定高度的區塊時,上下邊緣的漸層能提示「還有內容」——但到頂了還留著上方漸層,就會把第一筆蓋得半透明。這個元件的漸層高度直接等於剩餘可捲距離(上限 maxFadeHeight):越接近頂端,上方漸層越薄,到頂完全消失;底部同理。可用 items + renderItem 輸出語意化的 <ul>,也可直接放 children;需要跑馬燈式的公告欄時,開 autoScroll 即可。

把這個效果裝進你的專案

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

npx webberui@latest add scroll-fade-list

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

Playground

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

76
320
24
編輯中的呼叫預設屬性
<ScrollFadeList/>

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

安裝

npx webberui@latest add https://webberui.com/r/scroll-fade-list.json

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

使用

import { ScrollFadeList } from "@/components/ui/scroll-fade-list";

const areas = [
  { name: "臺北市中正區", zip: "100" },
  { name: "臺中市西屯區", zip: "407" },
  { name: "高雄市苓雅區", zip: "802" },
];

<ScrollFadeList
  items={areas}
  getKey={(a) => a.zip}
  height={280}
  label="配送地區"
  renderItem={(a) => (
    <div className="flex justify-between px-3 py-2 text-sm">
      <span>{a.name}</span>
      <span className="font-mono tabular-nums">{a.zip}</span>
    </div>
  )}
/>

放在非白色底上時,覆寫 --wb-sfl-bg 讓漸層的實色端與底色一致:

<ScrollFadeList
  className="[--wb-sfl-bg:#fafafa] dark:[--wb-sfl-bg:#171717]"
  autoScroll
>
  {/* 任意內容 */}
</ScrollFadeList>

Props

Prop型別預設值說明
itemsT[]—清單資料;與 renderItem、getKey 一組使用,提供時輸出 <ul>/<li> 結構,否則改渲染 children
renderItem(item: T, index: number) => ReactNode—每筆資料的渲染函式;未提供時以 String(item) 顯示
getKey(item: T, index: number) => Key—每筆資料的 key;未提供時用索引
childrenReactNode—未使用 items 時,直接放進捲動容器的內容
maxFadeHeightnumber76上下漸隱的最大高度(px);實際高度 = min(剩餘可捲距離, 此值)
heightnumber | string320捲動區高度;數字視為 px,也可傳任何 CSS 長度字串
autoScrollbooleanfalse自動往下捲動,到底回到頂端重來;滑鼠移入、鍵盤聚焦、觸控時暫停,減少動態效果時忽略
gutternumber10右側讓給捲軸的寬度(px),漸層不覆蓋這一段
labelstring"清單"捲動區的無障礙名稱(role="region" 的 aria-label)
listClassNamestring—透傳到 <ul>(items 模式)或內容包裹層(children 模式)
classNamestring—透傳到最外層容器

CSS 變數

欄位型別預設值說明
--wb-sfl-bgcolor#ffffff(dark:#0a0a0a)漸層的實色端,需與清單所在底色一致
--wb-sfl-auto-speednumber24自動捲動速度(px/秒),元件每秒重讀一次
--top-fade-heightlength—由元件於捲動時寫入的上方漸層高度,勿手動設定
--bottom-fade-heightlength—由元件於捲動時寫入的下方漸層高度,勿手動設定

細節

  • 捲動事件以 passive: true 監聽並用 requestAnimationFrame 節流;每幀量測 scrollTop(到頂距離)與 scrollHeight − clientHeight − scrollTop(到底距離),各自夾在 0 到 maxFadeHeight 之間,以 style.setProperty 直接寫進 CSS 變數,不經 React state,捲動時清單不會重新渲染。
  • 漸層高度刻意不加 transition:它就是剩餘距離本身,加動畫只會落後於手指。
  • ResizeObserver 同時監看捲動容器與內容,資料增減、字型載入或換行改變內容高度時會重算。
  • 漸層是外層容器的 ::before/::after,pointer-events: none 不擋點擊;右側讓出 gutter 寬度,不蓋住捲軸。捲動容器設定 scrollbar-gutter: stable 與 overscroll-behavior: contain。
  • 自動捲動以浮點累加器記錄位置,每幀推進不到 1px 也能平順移動;使用者手動捲過後會從新位置接續。觸控結束後延遲約 1.5 秒才恢復,讓慣性捲動先跑完。

可及性

  • 捲動容器為 role="region" 並以 label 作為 aria-label,tabIndex=0 讓鍵盤使用者能聚焦後用方向鍵、Page Up/Page Down 捲動,聚焦時顯示 focus-visible 外框
  • items 模式輸出帶 role="list" 的 <ul>/<li>,螢幕閱讀器會朗讀項目數
  • 漸層是不含文字的偽元素,不會被輔助科技讀出,也不攔截指標事件
  • 自動捲動在滑鼠移入、容器內任一元素取得焦點、觸控時暫停,不會在使用者閱讀或操作時把內容捲走
  • 使用者系統開啟「減少動態效果」時,漸層照常(它不是動畫),只停用 autoScroll