優化UI性能
1)算什麼「快速」
TTFB(第一個字節之前的時間)是服務器/CDN的快速響應。
LCP(Largest Contentful Paint)-「主要」內容很快出現。
INP (Interaction to Next Paint)-在交互時響應。
CLS (Cumulative Layout Shift)-不存在「抖動」接口。
TTI (Time to Interactive)-當一切都已經響應時。
建議的地標:LCP ≤ 2。5 s,INP ≤ 200毫秒,CLS ≤ 0。1(對於第75個實際用戶)。
2)過程: 衡量→發現瓶頸→提交預算
1.測量:RUM(實際用戶,按國家/網絡/Devaysom分級)+合成(燈塔/觀察者)。
2.查找:Performance Profiler(長任務>50 ms,布局擦除,多余渲染)。
3.記錄:預算(JS/CSS/字體重量,LCP/INP)和CI中的「紅線」。
3)網絡和資源下載
3.1個HTTP和優先級
啟用HTTP/2/3,Brotli壓縮。
「preconnect」到關鍵域;「dns-prefetch」到次要域。
關鍵資源的「preload」(英雄圖像,主字體)。
支持的"fetchpriority="high/low"和"priority"線索。
3.2緩存
帶有文件哈希的靜態:「Cache-Control:public,max-age=31536000,immutable」。
HTML是通過CDN的簡短TTL+stale-while-revalidate。
用於離線/重復訪問的ETag/Last-Modified和Service Worker。
4)代碼: 小,後來,「更平等」
4.1組裝
Tree-shaking, minify (в т.ч. dead-code-elim).
在路由/小部件上進行代碼分割,動態導入。
避免在基本樂隊(瞬間→ Intl/Day中出現「全局」重包。js).
4.2 HTML渲染和交付
SSR/ISR/流媒體:首先提供框架和主內容。
Partial/Islands hydration:僅對交互式區域進行氫化。
Defer都是非關鍵的:「<script type=」module「 defer>」。
4.3反應細節(如果使用React)
`React.懶惰的小部件的lazy'+ 'Suspense'。
「startTransition」和「useDeferredValue」用於重型過濾器/搜索。
RSC(服務器組件)-服務器上的計算小於客戶端上的JS。
堆棧中的選擇器(zustand/redux):將組件簽入片段,而非整個堆棧。
5)渲染和狀態: 其中「剎車」
5.1 Reenders隔離
粉碎大組件,模因(「memo」,「useMemo」,「useCallback」)。
列表密鑰是穩定的;不要在沒有必要的情況下創建新的功能/設施。
避免頻繁更改的數據的「全局」上下文,使用選擇器或事件總線。
5.2虛擬化和大列表
工作表/表格→虛擬化(渲染窗口)。
分離/不定式滾動帶背壓盤(不要一次裝載10萬行)。
Wewport外的重小部件延遲初始化。
5.3 Layout & paint
content-visibility: auto;對於隱藏部分(瀏覽器不會渲染不可見部分)。
contain和「contain-intrinsic-size」可預測尺寸。
避免頻繁讀取布局輸入記錄(布局擦除);分組測量。
使用劑量(否則多余的內存/圖層)。
6)圖像和圖形
格式:AVIF/WebP(PNG/JPEG上的後退)。
響應方法:「srcset」+「sizes」,基於視網膜的density。
非英雄圖像的'loading='lazy';priority/preload-僅適用於LCP候選人。
固定尺寸的播放器→沒有CLS跳躍。
Canvas/圖表:用於計算的offscreen-canvas和Web Worker;重新繪制。
7)字體和文字
一到兩個可變字體代替許多字體。
「font-display: swap'/' optional」, preload for main driving。
「size-adjust」以減少字體替換時的「跳躍」。
具有相似度量的本地fallback字體。
8) CSS和動畫
關鍵的CSS入口(<14-20 kB),其余的是延遲。
刪除未使用的樣式(Purge/CSSTree)。
如果可能的話,在transform/opacity上進行動畫;尊重「prefers-reduced-motion」。
避免深層級聯和爆炸性選擇器。
9) Web Workers,線程和繁重任務
所有CPU重都在Worker中(解析、排序、聚合、ML)。
流媒體API(「ReadableStream」,帶有線程的「fetch」)用於長響應。
通過「requestIdleCallback」/microtaski將任務分解到襪子上,以保持響應能力。
10)布局穩定性(CLS)
在LCP元素下方保留一個位置(圖像/小部件)。
不要在沒有固定尺寸的情況下插入橫幅/磁帶。
不對稱的tultips/tosts-不移動內容;使用圖層/門戶。
11)嗅探示例
關鍵字體和LCP影像
html
<link rel="preload" href="/fonts/Inter. var. woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" as="image" href="/hero. avif" imagesrcset="/hero. avif 1x, /hero@2x. avif 2x" fetchpriority="high">
小部件的懶惰和安全初始化
js const Widget = React. lazy(() => import('./Widget'));
function Section() {
const inView = useInViewport('#sec');
return <div id="sec">{inView? <React. Suspense fallback={null}><Widget/></React. Suspense>: null}</div>;
}
穩定布局
css
.hero {
content-visibility: auto;
contain: layout paint;
contain-intrinsic-size: 720px 320px ;/LCP reserve/
}
12)回歸控制和預算
Bundle-budget:通用JS ≤ N kB,CSS ≤ M kB,initial-chunk ≤ KB。
CI(模擬)+RUM-alerta中的Web-Vitals(在感應器上)。
樂隊分析:PR中的source-map-explorer/分析儀。
組件的性能基準(10k元素渲染,反應時間)。
13)反模式
在第一個屏幕上裝載「全部和一次」:圖形,編輯,地圖。
巨大的全球州→級聯的重塑。
圖像大小為2-4 ×,沒有「srcset/sizes」。
主流上的長同步循環。
「outline: none」和定制焦點沒有優化-幹擾渲染指標。
通過「頂部/左側」進行動畫(打破布局並調用reflow)。
14)屏幕支票清單
[] LCP ≤ 2.3 G/mobile流量為5 c,CLS ≤ 0。1、INP ≤ 200毫秒
- 關鍵資源:優先事項/優先事項;剩下的是defer/lazy
- 樂隊:代碼分裂,沒有額外的依賴性
- 清單/表虛擬化,重小部件延遲初始化
- 圖片:AVIF/WebP,「srcset/sizes」,「loading=」lazy「」
- 字體:variable+'font-display", preload只需要
- CSS:關鍵直線、Purge、「內容可視性」和「contain」在適當的情況下
- 重型計算的工人/空格
- 預算和Web-Vitals連接到dashbords/alert
15)實施計劃(3次叠代)
叠代1-快速勝利(1-2周)
包括Brotli/HTTP-2/3,CDN。資源的關鍵性CSS和前端LCP。
將重型小部件帶入動態導入。
圖像→ AVIF/WebP+「srcset」。字體:「字體顯示:交換」。
叠代2-結構改進(3-4周)
路線上的代碼分裂,樂隊分析,刪除「重型」自由。
列表虛擬化,內容可見,contain-intrinsic尺寸。
實施SSR/流媒體/島嶼(相關)。
帶有Web-Vitals的RUM,預算為CI。
叠代3-規模和可持續性(連續)
Workers/offscreen-canvas,計算戰鬥,startTransition/deferredValue。
定期進行筆試,回歸的自動摘要,團隊培訓。
16)迷你常見問題
什麼是移動上最快的速度?
減少原始JS,SSR/流媒體和 LCP圖像優化。
總是需要SSR嗎?
沒有。如果頁面動態交互且緩存不佳-islands/partial hydration可能會更好。
為什麼INP在「輕型」幫派下表現不佳?
可能是主線程上的冗長任務(排序、圖形)-在Worker中分解任務。
底線
快速UI是一組學科:網絡優先級和緩存,較小和較晚的樂隊,可預測的無跳躍渲染,經濟的圖像和字體,以及在現實世界中的持續度量控制。輸入預算,自動化檢查,教導團隊在每個步驟中考慮速度-因此界面將在今天和一年後保持快速。