效的底層邏輯:從視覺(jué)表達(dá)到交互狀態(tài)管理的完整指南)
最近一段時(shí)間我養(yǎng)成了一個(gè)不算太好的習(xí)慣打開(kāi)一個(gè)產(chǎn)品官網(wǎng)光盯著首頁(yè)的動(dòng)效就能看十幾秒。數(shù)字滾動(dòng)、卡片翻轉(zhuǎn)、鼠標(biāo)懸停后粒子擴(kuò)散、滾動(dòng)時(shí)元素一個(gè)個(gè)帶著緩動(dòng)進(jìn)場(chǎng)……很多時(shí)候甚至?xí)a(chǎn)生一個(gè)錯(cuò)覺(jué)——功能還沒(méi)用上動(dòng)效已經(jīng)把“品質(zhì)感”拉滿了。如果你也做前端、做產(chǎn)品設(shè)計(jì)、做獨(dú)立開(kāi)發(fā)應(yīng)該能感受到這股風(fēng)潮。UI 動(dòng)效現(xiàn)在確實(shí)“卷”到了一種新高度過(guò)去我們只關(guān)心按鈕 hover 變色、頁(yè)面淡入淡出現(xiàn)在團(tuán)隊(duì)在討論的是軌跡曲線、嵌套編排、視差滾動(dòng)、WebGL 粒子背景甚至把 3D 渲染直接嵌進(jìn) UI 界面里。但盯得越多我反而越覺(jué)得需要停下來(lái)問(wèn)一個(gè)問(wèn)題那些真正讓人“能看一天”的動(dòng)效到底贏在視覺(jué)上的炫還是贏在交互邏輯上的順我目前更傾向的答案是視覺(jué)動(dòng)效負(fù)責(zé)讓人眼前一亮交互邏輯才負(fù)責(zé)讓人留下來(lái)。這篇文章想把這層關(guān)系拆開(kāi)聊順便聊聊作為一個(gè)前端或者 UI 開(kāi)發(fā)怎么判斷一個(gè)動(dòng)效值不值得做以及落地時(shí)最容易踩的坑在哪里。1. 動(dòng)效卷的不是“動(dòng)”而是“為什么動(dòng)”1.1 我們現(xiàn)在看到的動(dòng)效已經(jīng)復(fù)雜到什么程度先說(shuō)一個(gè)直觀感受。最近幾年你打開(kāi)稍微“講究”一點(diǎn)的產(chǎn)品頁(yè)面幾乎每個(gè)層次都有動(dòng)效參與頁(yè)面級(jí)路由切換、滾動(dòng)視差、元素進(jìn)場(chǎng)退場(chǎng)組件級(jí)卡片翻轉(zhuǎn)、列表拖拽、彈窗展開(kāi)收起、按鈕狀態(tài)反饋界面裝飾級(jí)背景粒子、光效流動(dòng)、漸變旋轉(zhuǎn)、流光描邊數(shù)據(jù)可視化級(jí)圖表入場(chǎng)、數(shù)字滾動(dòng)、節(jié)點(diǎn)連線、地圖飛線AI 應(yīng)用級(jí)思考狀態(tài)、打字流、任務(wù)進(jìn)度、代理工作流的節(jié)點(diǎn)動(dòng)畫(huà)。這不是某一個(gè)領(lǐng)域的趨勢(shì)而是整個(gè)行業(yè)在往“界面即體驗(yàn)”的方向移動(dòng)。尤其是 AI 應(yīng)用大量出現(xiàn)之后動(dòng)效從“好看”變成了“解釋狀態(tài)”的手段模型在思考、正在執(zhí)行、等待輸入、輸出中都需要用動(dòng)效讓用戶理解當(dāng)前發(fā)生了什么。所以你會(huì)發(fā)現(xiàn)UI 動(dòng)效的“卷”不只體現(xiàn)在視覺(jué)花樣上還體現(xiàn)在它承擔(dān)的任務(wù)越來(lái)越多。一個(gè)動(dòng)效設(shè)計(jì)得好不好已經(jīng)不能只看它炫不炫還要看它能不能把事情說(shuō)清楚。1.2 視覺(jué)上“動(dòng)”和邏輯上“順”是兩回事這是我想強(qiáng)調(diào)的第一個(gè)判斷視覺(jué)動(dòng)效和交互邏輯是兩個(gè)維度的事情。一個(gè)動(dòng)效可以在視覺(jué)上非常出色比如充電動(dòng)畫(huà)的粒子匯聚、數(shù)據(jù)大屏上的流光飛線但它如果沒(méi)有回答“當(dāng)前處于什么狀態(tài)”“接下來(lái)會(huì)發(fā)生什么”這兩個(gè)問(wèn)題那它本質(zhì)上只是裝飾。一個(gè)交互邏輯可以非常嚴(yán)謹(jǐn)比如按鈕點(diǎn)擊后有三態(tài)反饋、加載過(guò)程有明確進(jìn)度、頁(yè)面切換遵循平臺(tái)規(guī)范哪怕動(dòng)畫(huà)本身很簡(jiǎn)單用戶也能感受到系統(tǒng)的穩(wěn)定和可預(yù)期。很多團(tuán)隊(duì)把精力放在前者覺(jué)得動(dòng)效越豐富越顯得有設(shè)計(jì)感。但實(shí)際用戶進(jìn)入產(chǎn)品后更多依賴的是后者來(lái)理解系統(tǒng)。真正厲害的產(chǎn)品通常不是把所有地方都加滿動(dòng)效而是在關(guān)鍵狀態(tài)切換、關(guān)鍵反饋節(jié)點(diǎn)上把動(dòng)效做精準(zhǔn)。所以我的主判斷是這一輪 UI 動(dòng)效的“卷”表面是視覺(jué)表現(xiàn)的軍備競(jìng)賽深層其實(shí)是交互邏輯的精細(xì)化競(jìng)爭(zhēng)。最終能在用戶心里留下“順滑、高級(jí)、懂我”這些印象的不是動(dòng)效數(shù)量而是動(dòng)效和行為之間的匹配度。2. 把動(dòng)效拆成表現(xiàn)層和邏輯層才能看懂好壞2.1 表現(xiàn)層你到底看到了什么視覺(jué)變化如果用工程語(yǔ)言拆解動(dòng)效可以分成兩層。表現(xiàn)層解決的是“看起來(lái)怎么變”。包括動(dòng)畫(huà)屬性位移、縮放、旋轉(zhuǎn)、透明度、顏色、濾鏡、遮罩、路徑變換緩動(dòng)曲線ease、ease-in-out、cubic-bezier、spring時(shí)長(zhǎng)短反饋通常 100ms 到 300ms頁(yè)面級(jí)過(guò)渡可能到 400ms 到 600ms空間感透視、景深、陰影、視差組合編排多個(gè)元素先后觸發(fā)的延遲差、交錯(cuò)進(jìn)場(chǎng)、父子聯(lián)動(dòng)。這一層是大多數(shù)視覺(jué)設(shè)計(jì)師和前端最常討論的部分。你在瀏覽器里看到“絲滑”本質(zhì)上是這些參數(shù)的組合效果。比如一個(gè)卡片翻轉(zhuǎn)如果只做 rotateY沒(méi)有同時(shí)做陰影、縮放和背景色的聯(lián)動(dòng)就會(huì)顯得很生硬。2.2 邏輯層動(dòng)效背后的狀態(tài)機(jī)邏輯層解決的是“為什么動(dòng)、動(dòng)到什么狀態(tài)、中斷了怎么辦”。它不直接產(chǎn)生視覺(jué)卻決定了一個(gè)動(dòng)效是否合理。邏輯層至少包括狀態(tài)映射從 A 狀態(tài)到 B 狀態(tài)的對(duì)應(yīng)關(guān)系觸發(fā)條件用戶點(diǎn)擊、鼠標(biāo)懸停、數(shù)據(jù)變化、滾動(dòng)進(jìn)入視口、網(wǎng)絡(luò)返回反饋語(yǔ)義成功、失敗、加載中、空狀態(tài)、禁用狀態(tài)中斷策略動(dòng)畫(huà)執(zhí)行一半能不能被打斷打斷后回到哪個(gè)狀態(tài)時(shí)長(zhǎng)與節(jié)奏設(shè)計(jì)階段一說(shuō)明什么、階段二說(shuō)明什么終態(tài)約定動(dòng)效結(jié)束后的靜態(tài)狀態(tài)是否承載完整信息。用我們最熟悉的按鈕來(lái)舉例。按鈕點(diǎn)擊后如果只是有一個(gè)縮放效果這叫表現(xiàn)層邏輯但是如果點(diǎn)擊后還有一個(gè)“加載中”狀態(tài)加載完成后變成“成功”狀態(tài)失敗則回到初始狀態(tài)并給出錯(cuò)誤提示這背后就是一個(gè)完整的狀態(tài)機(jī)。很多前端在實(shí)現(xiàn)復(fù)雜動(dòng)效時(shí)容易出問(wèn)題不是因?yàn)椴粫?huì)寫 CSS 或 Canvas而是狀態(tài)沒(méi)理清。狀態(tài)沒(méi)理清動(dòng)效做得越炫后面的維護(hù)成本越高。2.3 用生活場(chǎng)景理解這兩層我比較喜歡拿紅綠燈來(lái)類比。紅綠燈的視覺(jué)表現(xiàn)層是紅黃綠三種顏色切換這并不驚人但它背后的交互邏輯是完整狀態(tài)機(jī)紅燈停、綠燈行、黃燈提示切換中間還包含倒計(jì)時(shí)、閃爍等狀態(tài)提示。如果某個(gè)紅綠燈為了“炫”把紅綠燈做成了霓虹跑馬燈效果視覺(jué)上確實(shí)能看一天但司機(jī)的第一反應(yīng)不是“好美”而是“我現(xiàn)在該走還是該?!?。UI 動(dòng)效也一樣。用戶在界面里需要的不是每一幀都好看而是每一個(gè)狀態(tài)都清晰。一個(gè)動(dòng)效真正的高級(jí)感來(lái)自它讓用戶感覺(jué)到了控制感而不是被視覺(jué)牽著走。維度表現(xiàn)層邏輯層回答的問(wèn)題看起來(lái)怎么變化為什么變化、變化到哪個(gè)狀態(tài)典型要素屬性、曲線、時(shí)長(zhǎng)、編排狀態(tài)映射、觸發(fā)條件、反饋語(yǔ)義、中斷策略用戶感知炫、絲滑、精致清晰、流暢、可預(yù)期、被回應(yīng)工程關(guān)注點(diǎn)渲染性能、動(dòng)效表達(dá)狀態(tài)管理、事件時(shí)序、異常處理3. 前端落地的技術(shù)選型從 CSS 動(dòng)效到 Canvas / WebGL3.1 CSS 動(dòng)效大部分 UI 交互的基本盤如果你的動(dòng)效對(duì)象是常規(guī) UI 元素——按鈕、卡片、彈窗、列表、頁(yè)面切換CSS Transition 和 Keyframe 依然是成本最低、最穩(wěn)定的方案。CSS 動(dòng)效的核心優(yōu)勢(shì)是瀏覽器原生合成器處理 transform 和 opacity不需要 JavaScript 每幀參與。對(duì)常規(guī)交互來(lái)說(shuō)300ms 左右的過(guò)渡時(shí)長(zhǎng)配合一個(gè)合理的緩動(dòng)曲線已經(jīng)能讓界面有不錯(cuò)的質(zhì)感。比如這個(gè)按鈕按下反饋是很多產(chǎn)品里常見(jiàn)的寫法.button { transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms ease; } .button:active { transform: scale(0.96); }這里的關(guān)鍵不是代碼本身而是背后的小狀態(tài)機(jī)按下前、按下時(shí)、松開(kāi)后。CSS 能天然處理這個(gè)狀態(tài)切換但如果你需要在 press 狀態(tài)里觸發(fā)其他聯(lián)動(dòng)比如一個(gè) Loading 出現(xiàn)那就要配合類名切換或者狀態(tài)管理庫(kù)。落地建議常規(guī)組件動(dòng)效應(yīng)優(yōu)先選擇 CSS 實(shí)現(xiàn)因?yàn)樗恼{(diào)試成本最低、性能最可控、瀏覽器兼容性最好。復(fù)雜編排或跨組件動(dòng)畫(huà)再引入更重的方案。3.2 Canvas UI當(dāng)動(dòng)效進(jìn)入“每一幀都不一樣”的階段當(dāng)動(dòng)效不再是簡(jiǎn)單的狀態(tài)切換而是每幀都需要重新計(jì)算繪制時(shí)CSS 就會(huì)顯得吃力。典型場(chǎng)景包括粒子系統(tǒng)鼠標(biāo)移動(dòng)后有粒子跟隨或者擴(kuò)散數(shù)據(jù)可視化海量節(jié)點(diǎn)連線、實(shí)時(shí)流量圖圖表動(dòng)畫(huà)柱狀圖增長(zhǎng)、折線圖軌跡、餅圖展開(kāi)復(fù)雜路徑元素沿貝塞爾曲線飛行、不規(guī)則軌跡運(yùn)動(dòng)。這類動(dòng)效用 Canvas 更合適。Canvas 的核心思路是你自己控制每一幀的繪制內(nèi)容自由度比 CSS 大很多。但隨之而來(lái)的代價(jià)是需要自己管理動(dòng)畫(huà)循環(huán)的啟動(dòng)和銷毀設(shè)備像素比適配避免畫(huà)面模糊幀率控制和按需渲染內(nèi)存釋放避免長(zhǎng)時(shí)間運(yùn)行后越來(lái)越卡。一個(gè)常見(jiàn)的 Canvas 動(dòng)畫(huà)循環(huán)骨架是這樣function renderFrame(timestamp) { // 根據(jù)時(shí)間戳計(jì)算當(dāng)前幀的狀態(tài) // 清空畫(huà)布或增量擦除 // 繪制粒子、路徑、圖形 requestAnimationFrame(renderFrame); } requestAnimationFrame(renderFrame);這里最容易踩的坑是動(dòng)畫(huà)一直在跑哪怕頁(yè)面已經(jīng)不可見(jiàn)或者是每幀都全量重繪整張畫(huà)布導(dǎo)致 CPU 和 GPU 占用偏高。我的習(xí)慣是粒子數(shù)量、繪制范圍、交互響應(yīng)頻率都設(shè)置上限并且在頁(yè)面切換到后臺(tái)時(shí)暫停循環(huán)。很多“明明只是一個(gè)粒子背景CPU 卻一直拉滿”的問(wèn)題都是因?yàn)闆](méi)有做生命周期管理。3.3 WebGL / 3D 渲染沉浸感強(qiáng)但先問(wèn)有沒(méi)有必要現(xiàn)在很多科技感官網(wǎng)喜歡上 3D 地球、3D 模型、視角旋轉(zhuǎn)、流體光照這類效果。這些效果通常依賴 WebGL 或 WebGPU 渲染能帶來(lái)很強(qiáng)的視覺(jué)沖擊。但這類方案的成本也很直觀包體變大加載時(shí)間變長(zhǎng)性能受設(shè)備影響明顯低端機(jī)上可能發(fā)熱掉電需要專門的 3D 資產(chǎn)和調(diào)參經(jīng)驗(yàn)和業(yè)務(wù) UI 的耦合成本高測(cè)試回歸麻煩。我并不是反對(duì)在 UI 里加 3D。只是在決策時(shí)建議多問(wèn)一個(gè)“為什么”如果是產(chǎn)品演示、品牌站、營(yíng)銷頁(yè)目的是讓人記住視覺(jué)沖擊那 3D 是合理的如果是一個(gè)工具型產(chǎn)品用戶每天要執(zhí)行幾百次操作那 3D 動(dòng)效更應(yīng)該在空狀態(tài)、品牌區(qū)、加載緩沖這類非關(guān)鍵路徑上出現(xiàn)而不是占滿主操作區(qū)。3.4 動(dòng)效樣式庫(kù)可以用但別把“引入庫(kù)”當(dāng)作“設(shè)計(jì)完成”現(xiàn)在生態(tài)里有很多動(dòng)效庫(kù)、樣式庫(kù)、組件庫(kù)比如常見(jiàn)的 CSS 動(dòng)效樣式庫(kù)、交互動(dòng)效庫(kù)、UI 組件庫(kù)。熱詞里也出現(xiàn)了大量 UI 相關(guān)搜索說(shuō)明大家其實(shí)在用各種庫(kù)來(lái)加速落地。動(dòng)效庫(kù)能解決“怎么寫出來(lái)”的問(wèn)題但解決不了“該不該寫、寫在這個(gè)位置對(duì)不對(duì)”的問(wèn)題。引入一個(gè)庫(kù)最多節(jié)省開(kāi)發(fā)時(shí)間但動(dòng)效是否和業(yè)務(wù)邏輯匹配還是要靠產(chǎn)品、設(shè)計(jì)和前端一起判斷。從工程經(jīng)驗(yàn)看我更建議小型項(xiàng)目或原型驗(yàn)證直接用 CSS 少量腳本成本最低中大型項(xiàng)目?jī)?yōu)先用設(shè)計(jì)系統(tǒng)里沉淀好的動(dòng)效 token比如統(tǒng)一時(shí)長(zhǎng)、統(tǒng)一緩動(dòng)、統(tǒng)一動(dòng)效類別可視化項(xiàng)目引入 Canvas 繪圖方案而不是硬用 CSS 模擬需要極強(qiáng)沉浸感再評(píng)估 WebGL 方案并且提前確認(rèn)性能基線。4. 交互邏輯才是“能看一天”的真正原因4.1 真正耐看的動(dòng)效往往因?yàn)檫壿嬐暾氐綐?biāo)題里的“這種交互邏輯我能看一天”。為什么有些動(dòng)效你會(huì)反復(fù)想看甚至愿意一直操作它我觀察到一個(gè)規(guī)律那些耐看的界面通常動(dòng)效背后有完整的邏輯反饋。你點(diǎn)擊一個(gè)按鈕它先有一個(gè)按壓反饋你松開(kāi)它有一個(gè)回彈隨后加載狀態(tài)出現(xiàn)數(shù)據(jù)返回后內(nèi)容平滑過(guò)渡如果失敗有明確的失敗反饋并且告訴你下一步可以做什么。這一連串過(guò)程其實(shí)就是一個(gè)完整的交互閉環(huán)。視覺(jué)上的“好看”只是這層閉環(huán)的皮膚。真正讓用戶覺(jué)得“順”的是每個(gè)節(jié)點(diǎn)都有回應(yīng)每個(gè)狀態(tài)都符合預(yù)期每次操作都不會(huì)讓用戶等待后陷入迷茫。4.2 動(dòng)態(tài)“講述”狀態(tài)而不是制造迷惑動(dòng)效在使用中有一個(gè)核心任務(wù)講述狀態(tài)變化。舉個(gè)例子。列表里新插入一條數(shù)據(jù)時(shí)如果直接閃現(xiàn)在列表中用戶可能意識(shí)不到變化。如果有一個(gè)“新數(shù)據(jù)滑入并展開(kāi)”的過(guò)程用戶就能明確知道這里發(fā)生了一次插入。這個(gè)過(guò)程本身并不復(fù)雜但它完成了狀態(tài)講述。反過(guò)來(lái)如果頁(yè)面一直在做各種背景流動(dòng)、旋轉(zhuǎn)、流光用戶反而會(huì)分不清到底有哪些信息是新增的。這就是“無(wú)效動(dòng)效”和“有效動(dòng)效”的區(qū)別。判斷一個(gè)動(dòng)效是否有效有一個(gè)很簡(jiǎn)單的標(biāo)準(zhǔn)如果去掉它用戶是否會(huì)損失一些理解信息的線索如果沒(méi)有任何損失那這個(gè)動(dòng)效更多是氛圍裝飾如果去掉后用戶搞不清狀態(tài)轉(zhuǎn)換那它就是必要的交互邏輯。4.3 動(dòng)效的高級(jí)感來(lái)自克制和可預(yù)期有很多人把“能動(dòng)就行”理解成“所有地方都要?jiǎng)印?。但?dòng)效一旦過(guò)量用戶很快就會(huì)進(jìn)入“視覺(jué)疲勞”狀態(tài)。更嚴(yán)重的是動(dòng)效會(huì)拖慢操作路徑。實(shí)際產(chǎn)品里用戶第一個(gè)任務(wù)往往是盡快完成操作。動(dòng)效如果超過(guò) 300ms 還沒(méi)有完成就會(huì)開(kāi)始讓用戶感到等待。頁(yè)面級(jí)過(guò)渡超過(guò) 500ms 時(shí)用戶的耐心已經(jīng)接近臨界點(diǎn)。所以更合理的思路是在關(guān)鍵反饋處使用動(dòng)效在非關(guān)鍵裝飾處控制動(dòng)效密度。所謂“高級(jí)”不來(lái)自動(dòng)效數(shù)量多而來(lái)自動(dòng)效出現(xiàn)的位置精準(zhǔn)、每一次出現(xiàn)都有意義。這里可以沉淀一個(gè)交互反饋設(shè)計(jì)順序找到所有狀態(tài)切換點(diǎn)先保證切換邏輯完整狀態(tài)、反饋、異常兜底再為每個(gè)切換點(diǎn)選擇合適動(dòng)效強(qiáng)度在用戶高頻操作路徑上盡量縮短時(shí)長(zhǎng)在品牌展示或頁(yè)面首屏中加入少量表現(xiàn)層動(dòng)效制造記憶點(diǎn)。4.4 一個(gè)能“看一天”的界面多半有敘事層級(jí)我后來(lái)想了想“看一天”這個(gè)體驗(yàn)的來(lái)源。它不來(lái)自某個(gè)單一動(dòng)畫(huà)而是來(lái)自一種敘事感。一個(gè)頁(yè)面往下滾背景視差慢慢拉開(kāi)卡片逐張浮現(xiàn)細(xì)節(jié)逐層展開(kāi)點(diǎn)擊一個(gè)按鈕有反饋切換一個(gè) Tab有過(guò)渡每一步操作界面都在用動(dòng)效告訴你“你正處于哪里”“接下來(lái)可以去哪里”。這種體驗(yàn)就像看一部鏡頭語(yǔ)言很好的電影每一幀的變化都在推進(jìn)敘事而不是為了炫技。UI 動(dòng)效如果也能做到這一點(diǎn)用戶自然愿意多停留一會(huì)兒不是被強(qiáng)留而是因?yàn)槔斫饨缑娌毁M(fèi)力。5. 工程化落地性能、體驗(yàn)、可維護(hù)性一個(gè)都不能少5.1 動(dòng)效不是寫完就結(jié)束而是進(jìn)入長(zhǎng)期維護(hù)環(huán)節(jié)很多開(kāi)發(fā)者在寫動(dòng)效時(shí)只關(guān)注“第一版能不能跑出來(lái)”忽略了后面半年、一年的維護(hù)問(wèn)題。這里說(shuō)的維護(hù)不是改代碼而是整個(gè)動(dòng)效體系能不能被團(tuán)隊(duì)持續(xù)使用。如果你只是一個(gè)人做一個(gè)臨時(shí)頁(yè)面動(dòng)效怎么寫都行。但當(dāng)產(chǎn)品有多個(gè)頁(yè)面、多個(gè)角色、多個(gè)迭代版本時(shí)動(dòng)效就必須工程化統(tǒng)一時(shí)長(zhǎng)不建議每個(gè)開(kāi)發(fā)者自己拍腦袋定 200ms 還是 400ms統(tǒng)一緩動(dòng)曲線按鈕、卡片、彈窗、頁(yè)面過(guò)渡最好有統(tǒng)一節(jié)奏統(tǒng)一動(dòng)效類別進(jìn)場(chǎng)、退場(chǎng)、反饋、強(qiáng)調(diào)應(yīng)該形成命名規(guī)范統(tǒng)一受控方式通過(guò) CSS 變量或配置項(xiàng)控制而不是散落在每個(gè)組件里。最簡(jiǎn)單的實(shí)踐是定義幾個(gè)動(dòng)效 token:root { --duration-fast: 150ms; --duration-base: 250ms; --duration-slow: 400ms; --ease-standard: cubic-bezier(0.2, 0, 0, 1); --ease-emphasized: cubic-bezier(0.2, 0, 0, 1); --ease-exit: cubic-bezier(0.1, 0.8, 0.2, 1); }這樣至少能保證多個(gè)頁(yè)面的動(dòng)效節(jié)奏一致。后續(xù)想整體調(diào)整也只需要改這幾個(gè)變量。5.2 性能排查先看屬性再看重繪區(qū)域再看幀率動(dòng)效的常見(jiàn)性能問(wèn)題可以用一個(gè)排查鏈路來(lái)處理先確認(rèn)動(dòng)畫(huà)屬性優(yōu)先使用 transform 和 opacity避免直接改width、height、top、left這類會(huì)觸發(fā) layout 的屬性再看重繪區(qū)域動(dòng)效畫(huà)面占多大區(qū)域全屏粒子和局部小組件的成本完全不同再看幀率在瀏覽器 Performance 面板或真機(jī)上查看 FPS是否長(zhǎng)期低于 30再看資源占用CPU 和 GPU 占用是否異常內(nèi)存是否持續(xù)增長(zhǎng)最后看生命周期動(dòng)畫(huà)循環(huán)是否在頁(yè)面不可見(jiàn)時(shí)仍繼續(xù)。如果你的頁(yè)面加載后只是打開(kāi)界面什么都不做CPU 占用卻一直很高那大概率是動(dòng)效沒(méi)有做好“停止”和“空閑降級(jí)”。5.3 尊重系統(tǒng)“減少動(dòng)態(tài)效果”設(shè)置這是國(guó)內(nèi)團(tuán)隊(duì)經(jīng)常忽略的一點(diǎn)。很多操作系統(tǒng)提供了“減少動(dòng)態(tài)效果”或“關(guān)閉動(dòng)畫(huà)”的輔助功能選項(xiàng)。如果一個(gè)用戶明確表示自己不想看到過(guò)多動(dòng)態(tài)效果你的頁(yè)面應(yīng)該尊重這個(gè)設(shè)置降級(jí)到淡入淡出或直接靜態(tài)切換。實(shí)現(xiàn)方式通常不復(fù)雜media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }這種細(xì)節(jié)表面上是代碼問(wèn)題本質(zhì)上是動(dòng)效價(jià)值觀的問(wèn)題動(dòng)效是服務(wù)用戶理解信息的工具不是強(qiáng)制用戶接受的產(chǎn)品意志。需要時(shí)刻提醒自己動(dòng)效的邊界是要照顧到所有用戶包括那些對(duì)動(dòng)態(tài)效果敏感的人。5.4 可維護(hù)性還包含“如何下線”一個(gè)沒(méi)人提但很重要的問(wèn)題是動(dòng)效怎么下線。如果某個(gè)動(dòng)效上線后用戶反饋明顯反感或者后端接口耗時(shí)變化導(dǎo)致動(dòng)效時(shí)序錯(cuò)亂你能不能快速關(guān)掉它方案上建議所有非核心動(dòng)效都做成配置開(kāi)關(guān)。不要讓動(dòng)效邏輯和業(yè)務(wù)邏輯強(qiáng)耦合在同一個(gè)文件里。比較好的做法是動(dòng)畫(huà)觸發(fā)條件通過(guò)狀態(tài)字段控制視覺(jué)反饋通過(guò) CSS 類名控制裝飾性動(dòng)效通過(guò)全局配置開(kāi)關(guān)控制核心狀態(tài)切換動(dòng)效單獨(dú)封裝不要散落在業(yè)務(wù)代碼里。這樣一旦需要撤掉某個(gè)動(dòng)效不至于改動(dòng)大量業(yè)務(wù)代碼。6. 一個(gè)可復(fù)用的動(dòng)效評(píng)估框架給每個(gè)動(dòng)效做一次“體檢”6.1 六步快速評(píng)估既然動(dòng)效容易陷入“好看優(yōu)先”的誤區(qū)我梳理了一個(gè)評(píng)估框架用來(lái)判斷一個(gè) UI 動(dòng)效是否真的值得做。不限于設(shè)計(jì)評(píng)審前端自己也可以先過(guò)一遍。評(píng)估項(xiàng)核心問(wèn)題合格標(biāo)準(zhǔn)目的這個(gè)動(dòng)效是為了說(shuō)明狀態(tài)還是為了裝飾氛圍至少有一個(gè)明確目的狀態(tài)映射用戶能知道動(dòng)效前是什么狀態(tài)、動(dòng)效后是什么狀態(tài)嗎前后狀態(tài)清晰可辨反饋閉環(huán)成功、失敗、加載、空狀態(tài)都有對(duì)應(yīng)表現(xiàn)嗎關(guān)鍵狀態(tài)有兜底反饋時(shí)長(zhǎng)節(jié)奏高頻操作是否足夠快頁(yè)面過(guò)渡是否在合理范圍高頻操作不超過(guò) 250ms性能成本是否只用了 transform / opacity是否有過(guò)度重繪幀率穩(wěn)定CPU 占用合理可降級(jí)是否尊重“減少動(dòng)態(tài)效果”是否可以關(guān)閉有降級(jí)策略在項(xiàng)目評(píng)審中我一般會(huì)建議先把“目的”和“狀態(tài)映射”兩項(xiàng)確認(rèn)后再談視覺(jué)方向。因?yàn)槿绻麆?dòng)效背后的狀態(tài)邏輯沒(méi)想清楚視覺(jué)做得再漂亮最后也會(huì)在返工中消耗大量時(shí)間。6.2 什么時(shí)候應(yīng)該砍掉動(dòng)效同樣重要的問(wèn)題是什么時(shí)候不做動(dòng)效。至少有幾類場(chǎng)景動(dòng)效是明顯不合適的操作路徑非常高頻比如數(shù)據(jù)列表中每行都有“編輯”“刪除”按鈕如果每點(diǎn)擊一次都來(lái)一段長(zhǎng)動(dòng)畫(huà)用戶會(huì)被拖死內(nèi)容本身變化極快例如行情列表、日志流如果每一條變化都有大動(dòng)效界面必然視覺(jué)混亂后端響應(yīng)不穩(wěn)定動(dòng)效時(shí)序又強(qiáng)依賴接口返回時(shí)間很容易出現(xiàn)動(dòng)畫(huà)已經(jīng)播完、數(shù)據(jù)還沒(méi)回來(lái)的尷尬場(chǎng)景團(tuán)隊(duì)沒(méi)有維護(hù)余力動(dòng)效上線后沒(méi)人負(fù)責(zé)調(diào)優(yōu)堆疊得越多后期就越難收拾。所以說(shuō)判斷一個(gè)動(dòng)效做得好不好不只是“做出來(lái)很炫”還包括“在哪些場(chǎng)景下忍住不做”這個(gè)決策能力。6.3 給前端和設(shè)計(jì)協(xié)作時(shí)的三個(gè)建議動(dòng)效從設(shè)計(jì)稿到線上實(shí)現(xiàn)中間存在很多信息損耗。最常見(jiàn)的損耗來(lái)自設(shè)計(jì)稿只有最終靜態(tài)效果沒(méi)有過(guò)程狀態(tài)。所以在協(xié)作時(shí)我會(huì)建議設(shè)計(jì)提供關(guān)鍵幀說(shuō)明不只是給出“開(kāi)始”和“結(jié)束”還要說(shuō)明中間哪些階段是重點(diǎn)前端主動(dòng)補(bǔ)充時(shí)序一個(gè)動(dòng)效是 200ms 還是 400ms要主動(dòng)驗(yàn)證并和設(shè)計(jì)對(duì)齊用原型做快速驗(yàn)證在寫進(jìn)真實(shí)業(yè)務(wù)代碼之前先用小頁(yè)面把動(dòng)效跑一下確認(rèn)手感?!笆指小边@件事很難從靜態(tài)稿里確定只能靠真實(shí)交互來(lái)感受。很多團(tuán)隊(duì)看設(shè)計(jì)稿覺(jué)得好看實(shí)現(xiàn)完又覺(jué)得不夠順原因往往不是開(kāi)發(fā)能力問(wèn)題而是缺乏過(guò)程驗(yàn)證環(huán)節(jié)。7. 結(jié)尾視覺(jué)負(fù)責(zé)第一眼交互邏輯負(fù)責(zé)一直看下去再回到開(kāi)頭那個(gè)問(wèn)題UI 動(dòng)效卷成這樣我們到底該卷什么我的答案是視覺(jué)表現(xiàn)可以卷但千萬(wàn)別只卷視覺(jué)。真正讓一個(gè)界面有“能看一天”潛質(zhì)的是背后的交互邏輯足夠嚴(yán)謹(jǐn)、克制、可預(yù)期。每一個(gè)點(diǎn)擊都有回應(yīng)每一個(gè)狀態(tài)切換都清晰每一個(gè)動(dòng)效出現(xiàn)的位置都經(jīng)過(guò)思考。用戶感受到的不是“這里動(dòng)效好炫”而是“這個(gè)系統(tǒng)用起來(lái)好順”。這也是我最近一段時(shí)間最大的體會(huì)。好看的動(dòng)效是設(shè)計(jì)能力但把動(dòng)效放到正確的位置、在正確的時(shí)機(jī)出現(xiàn)、又能在不需要的時(shí)候安靜退場(chǎng)才是更深一層的工程能力。如果你手頭正在做一個(gè)動(dòng)效特別多的界面建議先別急著加新動(dòng)畫(huà)。從已有動(dòng)效里挑幾個(gè)用前面那個(gè)六步框架過(guò)一遍把目的不明確、狀態(tài)映射混亂、時(shí)長(zhǎng)過(guò)長(zhǎng)的動(dòng)效先砍掉或者簡(jiǎn)化。你會(huì)發(fā)現(xiàn)界面反而更舒服。如果下一次再看到一個(gè)讓你停下來(lái)盯半天的界面提醒自己多看一眼是視覺(jué)先吸引了你還是邏輯讓你一直想看下去答案更靠近后者的時(shí)候這個(gè)界面大概率不是靠堆動(dòng)效堆出來(lái)的而是靠一套成熟的交互邏輯撐起來(lái)的。