Communitygithub.com

igal-commits/animating-web-pages

用於在網頁上添加或修正動畫效果 — 捲動顯示、首頁進場與淡入淡出、環境背景循環、循環背景影片、圖片輪播、黏性元素 — 或當動畫卡頓、時機錯誤、在畫面外播放、或完全無法運作時使用。

animating-web-pages 是什麼?

這項技能專注於網頁動畫的機械層面:確保動畫能夠執行並且執行流暢。它適用於 Claude Code、Cursor 以及任何支援「技能」的 AI 代理平台。核心原則是:在調整動畫曲線之前,先證明動畫確實在你認為的元素上執行。技能涵蓋了動畫不執行的診斷方法(選擇器未匹配、觸發時機錯誤、隱藏分頁問題)、首頁進場與環境動畫的設計準則(如:進場時間應控制在 1.1 秒內、照片應淡出而非滑動)、捲動觸發動畫的實作(使用 88% 觸發閾值、60-90ms 的交錯延遲)、背景影片的正確處理方式(移除 autoplay,在首次進入時重新設定 currentTime)、以及消除卡頓的技巧。此外也深入說明 sticky 在 CSS Grid 中的行為、三種動畫降級方案(減少動畫偏好設定、無腳本情境、手機版),以及一份詳細的驗證清單。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/igal-commits/landing-page-skills/tree/HEAD/skills/animating-web-pages

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

動畫網頁

概述

網頁動畫的失敗有兩種形式:它不執行,或是執行得很糟糕。兩者都有特定的、可追查的原因。猜測緩動曲線是最後才該做的事,而不是第一步。

核心原則:在調整動畫之前,先證明它在你認為的元素上執行。

關於固定位置與滾動觸發場景的設計,請參閱 choreographing-scroll-stories。此技能專注於機械層面:讓動畫執行,並且執行流暢。

當動畫完全不執行時

請依序檢查。前三項幾乎涵蓋了所有情況。

症狀原因檢查方式
沒有任何東西移動,元素可見選擇器未匹配到任何元素在控制台執行 document.querySelectorAll(sel).length
沒有任何東西移動,元素不可見揭露效果設為 opacity: 0,但觸發器從未觸發檢查元素的計算樣式 opacity
淡入淡出效果從未發生兩個圖層都處於 opacity: 1;只有「啟動」規則存在必須有一個設定進入圖層為 0 的靜止規則
載入時立即觸發觸發器在版面配置穩定前就已評估應在 load 事件後執行,而非 DOMContentLoaded,以便圖片能決定頁面尺寸
觸發一次後就不再觸發once: true 加上元素又重新進入這是否是預期行為?
在隱藏分頁或無頭面板中不執行當 document.hidden 時,時間軸被暫停強制執行:gsap.ticker.lagSmoothing(0); gsap.ticker.tick()
觸發點偏差數百像素圖片載入後才測量觸發位置在載入和調整大小時執行 ScrollTrigger.refresh()(加上 200 毫秒防抖)

淡入淡出這個問題值得詳細說明,因為它在程式碼審查中看起來是正確的:

/* 單獨這段什麼都不做。 */
.tile.is-swapped .layer.is-alt { opacity: 1 }

/* 靜止狀態才是讓它成為動畫的關鍵。 */
.layer.is-alt { opacity: 0 }
.tile.is-swapped .layer.is-alt { opacity: 1 }

首頁進場與環境動畫

  • 標題要能快速可見。 將進場動畫剪裁到標題約在 1.1 秒內顯示。一個 3.8 秒的進場動畫就像一個載入畫面。
  • 照片透過從一個單元格淡出、進入另一個單元格來切換。它們永不滑動。 每張照片都是一個元素,絕不重複出現在畫面上,也不會在它的副本淡入時同時淡出。
  • 環境變化要緩慢且不規則。 每個磁貼每 1.8 到 3.4 秒變化一次,讓網格看起來像活著,而任何單一磁貼卻變化緩慢。不要為了讓每個磁貼變化得更快而縮短間隔。
  • 以輪次方式隨機排列。 每個磁貼在重複之前都會先變化一次,並且每次選擇都來自最近三次中較遠的那一半。
  • 暫停那些沒有人看到的東西。 環境循環會在螢幕外和隱藏分頁中停止,並在原來的地方恢復。
  • 進場動畫不會在每次返回時重播。 在進場動畫穩定後,除了環境層之外,沒有任何東西會移動。

捲動顯示

  • 只在載入時實際位於摺疊線下方的元素上設定 opacity: 0。全面隱藏所有元素意味著任何在摺疊線之上的元素都是不可見的,直到可能永遠不會發生的滾動出現。
  • 在 top 88% 觸發顯示,而不是完全交集。等待元素完全進入視野,代表動畫會在讀者已經看到它之後才執行。
  • 在同級元素之間交錯延遲,而非在元件內部。卡片之間 60-90ms,卡片內部為 0。
  • 每個群組使用一個觀察器進行批次處理,而非每個元素一個。

影片

自動播放的背景影片有一個普遍的問題:影片在螢幕外播放,一個觀察器暫停了它,等到讀者到達時,循環已經過了 15 秒,開頭的節奏就遺失了。

完全移除 autoplay 屬性。
在初始化時執行 pause() 和 load()。
只在第一次進入畫面時:currentTime = 0,然後執行 play()。

在 992px 以下或裝置像素比低於 1.5 時,提供 1x 檔案,並在影片解碼前提供一個海報幀。首頁的高流量影片也是頻寬消耗的大戶:請進行審計。

卡頓

靜態照片上的緩慢漂移是最常見的原因。Ken Burns 效果中,每幀移動低於約 1 像素時,會導致每一幀都重新取樣圖片,看起來像是閃爍而非移動。

  • 要嘛移動的幅度足夠成為動作,要嘛就完全不要移動。
  • 對於渲染影片中的靜止畫面,請逐位元組複製編碼後的幀,而不是重新編碼一個完全相同的幀。任何其他做法都會導致漂移。
  • 檢查循環接縫。如果第 0 幀與最後一幀不同,循環會每週期明顯跳動。測量它們之間的平均絕對差值。
  • 不要雙重平滑。一個平滑滾動函式庫加上一個沉重的 scrub 值,會導致頁面跟不上滾輪。當平滑滾動函式庫存在時,請使用 scrub: 0.2。

黏性元素

CSS Grid 內部的 position: sticky 是相對於網格區域來解析的,而不是整個容器。一個只跟自身內容一樣高的黏性元素沒有移動空間,並且會立即釋放。

.grid  { align-items: stretch }      /* 區域現在是全高的 */
.col   { position: static; height: 100% }
.inner { position: sticky; top: 10rem }

降級方案

每個動畫都有三個降級方案,必須寫在動畫規格中並進行測試:

  • 減少動畫。 prefers-reduced-motion: reduce 和一個 ?static 查詢參數,會渲染出堆疊好的、最終的狀態:沒有固定位置、沒有隱藏元素、每個場景都在結束狀態。也要涵蓋你添加的所有 CSS transition。列出動畫選擇器但忘記容器上的 transition,會導致顏色仍在滑動。
  • 無腳本。 所有東西保持可見。如果腳本從未啟動,約 3.5 秒後會添加一個 class,CSS 會顯示它底下的所有內容。
  • 手機版。 固定位置場景會堆疊起來。必須明確說明並進行測試。

驗證

不要僅從程式碼就報告動畫可以運作。請在頁面中確認:

  • 每個動畫群組的選擇器計數不為零
  • 在捲動之前,摺疊線上方元素的計算 opacity 為 1
  • 影片 currentTime 在它首次變為可見的瞬間低於 0.5 秒
  • 減少動畫模擬能讓頁面完全可讀且靜止
  • 無腳本情況下所有東西都保持可見
  • 沒有動畫作用於 width、height、top 或 left;使用 transform 和 opacity
  • 環境循環在螢幕外時不會進行任何樣式變更

紅旗警示

  • 在確認選擇器匹配之前就調整持續時間或緩動曲線
  • 一個 .is-active 規則沒有對應的靜止狀態規則
  • transition: all
  • 因為「感覺區塊很空」而添加的動畫
  • 會滑動的照片
  • 同一張照片在畫面上出現兩次

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相關技能