Scroll Zoom Reveal
一個可直接嵌入、無依賴的滾動效果:
- 固定全螢幕場景:標題位於填滿視窗的昏暗場景之上。
- 推軌 + 後拉:場景稍微穩定,然後「鏡頭」向後拉。場景其實是在筆電顯示器上(邊框與底座會進入視野)。
- 應用程式揭示:編輯器面板(工具列、大綱、屬性、時間軸)滑入,場景縮小到其視口面板中。
- 下方文字淡入(
data-zr-fade),接著是分頁式交叉淡出畫廊,搭配滑動藥丸切換開關。
所有可直接使用的檔案都在此檔案旁的 assets/ 資料夾中:
| 檔案 | 用途 |
|---|---|
assets/zoom-reveal.css | 所有樣式(主題記號位於 .zr) |
assets/zoom-reveal.js | 元件 + 淡入 + 畫廊。暴露 window.ZoomReveal,自動初始化 [data-zoom-reveal] / [data-zr-gallery] / [data-zr-fade] |
assets/oled-field.js | 可選。游標反應的 OLED 子像素場(window.OledField,自動初始化 [data-zr-oled])。樣式已包含在 zoom-reveal.css 中 |
assets/placeholder-scenes.js | 可選。在 Canvas 上程式化繪製預設佔位圖案(ZRScenes.drawCity、ZRScenes.drawCanyon),直到有真實圖片為止 |
assets/demo.html | 完整的運作頁面。請以此標記為起點。 |
如何在網站上使用
- 複製 assets 到專案中(例如
public/zoom-reveal/或src/vendor/zoom-reveal/)。只有當還沒有真實作品時才複製placeholder-scenes.js。 - 閱讀
assets/demo.html並複製<section class="zr" data-zoom-reveal>…</section>區塊(如果需要畫廊,也複製畫廊區塊)。請嚴格保持類別結構:
section.zr[data-zoom-reveal] ← 滾動長度在此定義 (--zr-length)
.zr-sticky ← 固定的 100vh 舞台
.zr-glow (可選的環境發光)
.zr-device ← 由 JS 縮放
.zr-lid > .zr-display
.zr-viewport > .zr-media > img | video | canvas ← 你的場景
.zr-chrome > .zr-panel.zr-toolbar / .zr-left / .zr-right / .zr-bottom (可選的應用程式 UI)
.zr-base (筆電底座;若是顯示器/平板則刪除此元素)
.zr-scrim + header.zr-intro ← 覆蓋在場景上的標題,會先淡出
.zr-caption ← 小說明文字,最後淡入
- 在
<head>中載入zoom-reveal.css,並在<body>結尾載入zoom-reveal.js。 - 更換媒體:用真實場景取代示範 Canvas:
- 圖片:
<img src="scene.avif" alt="" decoding="async">。匯出時請確保至少等於視口尺寸 × DPR(寬度 2560–3200px)。效果會以圖片填滿全螢幕開始。 - 滾動刮擦影片:
<video data-zr-scrub muted playsinline preload="auto" src="scene.mp4"></video>。JS 會將滾動進度對應到currentTime。請將影片編碼為每幀都是關鍵影格,以確保搜尋順暢:ffmpeg -i in.mov -c:v libx264 -g 1 -crf 22 -an -movflags +faststart scene.mp4。
- 圖片:
- 重寫所有文案(眉題、標題、說明文字、面板標籤、檔案名稱、畫廊標籤)以符合網站需求。切勿使用示範中虛構的「Orbit / Forge」文字。
- 透過
.zr上的記號設定主題:--zr-bg、--zr-fg、--zr-muted、--zr-accent、--zr-length(滾動距離,預設360vh)。
選項
可在屬性中傳遞 JSON,例如 data-zoom-reveal='{"maxWidth":1000,"viewport":{"top":0,"right":0,"bottom":0,"left":0}}',或在 JS 中建構:new ZoomReveal(el, options)。
| 選項 | 預設值 | 說明 |
|---|---|---|
maxWidth | 1180 | 最終顯示器最大寬度 (px) |
widthRatio / heightRatio | 0.82 / 0.64 | 最終顯示器相對於視口的大小比例 |
aspect | 0.625 | 顯示器高度 ÷ 寬度 (16:10)。手機約 2.16,超寬約 0.42 |
overscan | 1.04 | 顯示器開始時超出視口的距離(隱藏邊框) |
dolly | 1.14 | 媒體的初始內部縮放大小;最後會穩定到 1 |
lift | 0.035 | 裝置在結尾上升的高度 |
timeline | 見 JS | intro、dolly、zoom、chrome、caption 的 [start,end] 進度視窗 |
viewport | {top:6.5,right:21,bottom:22,left:15} | 應用程式 UI 內部場景面板的最終內邊距(顯示器尺寸的百分比)。如果要實現純「場景 → 裝置螢幕」後拉效果且無應用程式 UI,請將所有值設為 0 並刪除 .zr-chrome |
onProgress | — | 回呼函數 fn(p),p 為進度 0..1 |
事件:區塊會觸發 zr:resize 事件,帶有 {width, height, finalWidth},即媒體佈局時的像素尺寸。可用於調整 Canvas 大小或選擇圖片來源。
React / Next.js
在全域層級匯入 CSS。從標記中移除 data-zoom-reveal,並手動建構元件,以便與元件生命週期綁定(在 Next.js 中使用 'use client'):
useEffect(() => {
import('./zoom-reveal/zoom-reveal.js').then(() => { // 註冊 window.ZoomReveal
const zr = new window.ZoomReveal(ref.current, { maxWidth: 1100 });
const gal = galRef.current && new window.ZoomReveal.Gallery(galRef.current);
window.ZoomReveal.initFades();
cleanup = () => zr.destroy();
});
let cleanup = () => {};
return () => cleanup();
}, []);
請將 class 轉換為 className,並將 style="--v:78%" 轉換為 style={{'--v':'78%'}}。
OLED 像素場(游標懸停效果)
一個全出血的背景,由微小的 RGB 子像素條組成,光線昏暗。移動游標會攪動一個小型流體模擬。路徑上的像素會亮起、生長並從紫色變為青色、萊姆色再到暖白色,然後發光會沿游標方向漂移、擴散並淡出。點擊或輕觸會產生漣漪。當游標閒置時(以及在觸控螢幕上),一個緩慢的「幽靈游標」會保持效果活躍。渲染使用 WebGL1 片段著色器,模擬在小型 CPU 網格上運行,且僅在區塊可見時執行。若無 WebGL,則降級為 CSS 聚光燈效果。
可將其用於規格/統計區塊、英雄區塊或 CTA 區塊的背景。任何元素都適用:加上 class="zr-oled" data-zr-oled,在內部放置內容,並載入 zoom-reveal.css + oled-field.js。元件會自行插入 Canvas。請參閱 assets/demo.html 中的「OLED PIXEL FIELD」區塊。
<section class="zr-oled" data-zr-oled='{"cell":7}'>
<div class="your-content">…統計 / 標題…</div>
</section>
<script src="oled-field.js"></script>
| 選項 | 預設值 | 說明 |
|---|---|---|
cell | 6 | 每個像素的 CSS px 數量(3 條子像素)。5–9 看起來不錯;行動裝置上使用較大值以提升效能 |
radius | 2.4 | 畫筆半徑(以 cell 為單位) |
strength | 0.55 | 游標增加的光線強度。預設值刻意較為微妙;1 則較為醒目 |
decay | 0.94 | 每幀衰減;越高軌跡越長(0.92 短 … 0.97 長) |
flow | 0.55 | 發光沿游標方向漂移的距離 |
diffusion | 0.35 | 發光擴散的速度 |
base | 0.09 | 未點亮網格的亮度 |
palette | ['#5a3cff','#1fd6ff','#b6ff4a','#fff4d8'] | 4 種顏色,由低能量到高能量。可配合品牌色,例如暖色 ['#ff3c5a','#ff9a1f','#ffe14a','#fff8e8'] |
ambient / ripples | true | 閒置時顯示幽靈游標 / 點擊漣漪 |
若想獲得更醒目的外觀(更接近展示效果),可使用 {"radius":3.2,"strength":1,"decay":0.962,"flow":0.9}。在文字較多的區塊後方則保留微妙的預設值。
API:const f = new OledField(el, opts),f.pulse(clientX, clientY)(從程式碼觸發漣漪),f.destroy()(在 React 清理時呼叫)。在像素場上方的文字請加上柔和的深色 text-shadow,以便在明亮軌跡上保持可讀性。
常見問題(請在完成前檢查)
- 固定定位失效:如果
.zr的任何上層元素設有overflow: hidden/auto/clip或transform,請修正。若需隱藏水平溢位,請在body上使用overflow-x: clip。 - 請勿將
.zr包裹在會轉換頁面的平滑滾動函式庫中(如 Locomotive v4 等)。Lenis 沒問題。 - 裝置會以較大尺寸佈局然後縮小,因此媒體能保持銳利。請勿在
.zr-device內部使用固定 px 尺寸:請使用em(1em = 顯示器寬度的 1%)。 - 已處理減少動畫偏好設定:區塊會取消固定並顯示最終狀態;畫廊停止自動播放;OLED 場仍會對游標做出反應,但停止幽靈游標和漣漪。
- 動畫會在背景分頁中暫停(requestAnimationFrame 停止)。在瀏覽器面板中測試 OLED 場時,請保持頁面可見,否則看起來會凍結。
- 寬度小於約 500px 時,筆電看起來很小。在行動裝置上可考慮使用
{"widthRatio":0.92}或將aspect設為手機螢幕比例。 - 請在桌面和行動裝置寬度下,從上到下緩慢滾動測試。確認標題在後拉開始前淡出,起始時沒有邊框露出,且說明文字不與底座重疊。
- 請使用原創或獲得授權的作品與文案。本套件重現的是動態技術;請勿複製其他品牌的圖片、產品渲染或文字。
