mcpField
O
optimize

optimize

github.com/aladicf开发46553 次安装23 周前更新
代码仓库

关于 optimize

用于识别并修复前端性能问题的技能,面向需要提升加载速度和交互响应的项目。它强调先测量再优化,覆盖资源加载、渲染、动画、网络和 Core Web Vitals。

主要功能

  1. 01测量 Core Web Vitals、加载时间与交互延迟
  2. 02分析资源、代码包和运行时瓶颈
  3. 03优化图片、字体、CSS 与 JavaScript 加载
  4. 04检查布局抖动、渲染和动画性能
  5. 05提供网络及 Core Web Vitals 优化策略

适用场景

  1. 01排查页面加载缓慢的原因
  2. 02减少重复交互中的响应延迟
  3. 03优化长列表及图片密集界面
  4. 04改善 LCP、INP 或 CLS 指标

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aladicf/better-web-ui --skill optimize

安装后在 Claude Code 中输入/optimize确认已加载。

详细介绍

识别并修复性能问题,打造更快速、流畅的用户体验。

当图像性能问题与截图尺寸、图标缩放、裁剪策略或用户上传媒体的处理有关时,请参考图像处理。 当性能问题源于测量大量换行文本块、可变高度虚拟化、反复调整大小时的重新布局,或文本密集型 UI 中热路径上的 DOM 读取(如 offsetHeight / getBoundingClientRect())时,请参考文本布局预测。 当优化工作专门针对 LCP、INP 或 CLS,并且需要深入了解子项细分或实测与实验室测量指南时,请参考核心 Web 指标参考。 当项目需要为超长列表实现虚拟化且技术栈尚未确定时,请优先将 TanStack Virtual 作为 React、Vue、Angular、Solid 和 Svelte 生态系统中的默认无头虚拟化层。如果项目已使用其他虚拟化层,应优先保留现有方案。

必须完成的准备工作

用户通过 /optimize 启动此工作流。此技能激活后,加载 $frontend-design——其中包含设计原则、反模式和上下文收集协议。继续之前,请遵循该协议——如果尚无设计上下文,必须先加载 $setup。此外,还需收集:目标设备、性能限制,以及哪些用户交互感觉迟缓。

评估性能问题

了解当前性能并找出问题:

  1. 测量当前状态:
    • 核心 Web 指标:LCP、FID/INP、CLS 分数
    • 加载时间:可交互时间、首次内容绘制时间
  • 交互延迟:筛选、搜索、保存、打开面板、自动补全及其他重复操作的响应时间
  • 包大小:JavaScript、CSS、图像大小
  • 运行时性能:帧率、内存使用量、CPU 使用量
  • 网络:请求数量、载荷大小、瀑布图
  1. 找出瓶颈:
    • 慢在哪里?(初始加载?交互?动画?)
    • 是什么导致的?(大图像?开销大的 JavaScript?布局抖动?)
    • 问题有多严重?(能察觉?令人烦恼?造成阻塞?)
  • 影响哪些用户?(所有用户?窄屏布局用户?网络连接较慢的用户?)

关键:优化前后都要测量。过早优化会浪费时间。优化真正重要的部分。

优化策略

制定系统性的改进计划:

交互速度的多尔蒂阈值

常规交互应保持用户操作流畅。目标是让用户立即看到反馈,并尽可能在大约 400ms 内感受到交互已完成。

当处理时间会超过这一范围时:

  • 在约 100ms 内提供即时反馈(按下、激活、加载、乐观状态)
  • 尽早流式传输或展示部分内容,而不是等待全部内容就绪
  • 为常用路径预取可能的下一屏或数据
  • 优先使用骨架屏、乐观 UI 和渐进式渲染,而不是空白等待和通用加载动画

如果界面能够及时响应用户意图并保持操作连贯,就不要将加载动画作为高频操作的主要体验。

加载性能

优化图像:

  • 使用现代格式(WebP、AVIF)
  • 合理设置尺寸(不要为 300px 的显示区域加载 3000px 的图像)
  • 对首屏以下的图像启用延迟加载
  • 使用响应式图像(srcset、picture 元素)
  • 压缩图像(通常 80-85% 的质量损失肉眼难以察觉)
  • 使用 CDN 加快交付
<img
  src="hero.webp"
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
  sizes="(max-width: 400px) 400px, (max-width: 800px) 800px, 1200px"
  loading="lazy"
  alt="Hero image"
/>

现代图像格式策略(AVIF 和 WebP):

在视觉质量相当的情况下,AVIF 文件通常比 WebP 小 30-50%。WebP 的基础支持范围更广。两者搭配使用,并提供回退方案:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Hero image" loading="lazy">
</picture>

实用规则:

  • 对于主视觉图片、大型背景和照片密集型图库,在节省空间效果最显著的场景中生成 AVIF
  • 保留 WebP 作为回退格式,以覆盖更多浏览器
  • 不要为小图标或简单图形提供 AVIF,因为编码开销可能超过节省的空间
  • 尽可能使用能自动处理格式协商的图片 CDN
  • 在低端设备上测试 AVIF 的解码速度;虽然这种格式更小,但解码速度可能比 WebP 慢

减少 JavaScript 包体积:

  • 代码拆分(基于路由、基于组件)
  • Tree shaking(移除未使用的代码)
  • 移除未使用的依赖项
  • 延迟加载非关键代码
  • 对大型组件使用动态导入
// Lazy load heavy component
const HeavyChart = lazy(() => import('./HeavyChart'));

优化 CSS:

  • 移除未使用的 CSS
  • 将关键 CSS 内联,其余部分异步加载
  • 压缩 CSS 文件
  • 对独立区域使用 CSS containment

优化字体:

  • 使用 font-display: swap 或 optional
  • 对字体进行子集化(仅保留所需字符)
  • 预加载关键字体
  • 适当时使用系统字体
  • 限制加载的字体字重
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately */
  unicode-range: U+0020-007F; /* Basic Latin only */
}

字体子集化策略:

子集化会移除未使用的字形,大幅减小文件体积。完整的拉丁字体可能有 200KB;同一字体子集化为 Basic Latin 后,可能只有 20-30KB。

方法:

  • 静态子集化:按语言或文字系统(拉丁文、西里尔文、CJK)生成单独的字体文件,并通过 unicode-range 仅提供页面所需的字体文件
  • 动态子集化:使用 Google Fonts 等服务,或使用可自托管的子集化工具按需生成切片
  • 关键字形子集化:对于首屏主视觉文本,仅保留标题中使用的字符,并预加载该字体文件
/* Latin-only subset for body text */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-latin.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0020-007F, U+00A0-00FF;
}

/* Extended subset for other scripts, loaded only when needed */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-cyrillic.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0400-04FF;
}

子集化工具:

  • pyftsubset(fonttools),用于精准手动子集化
  • subfont,用于在构建时自动进行子集化
  • glyphhanger,用于提取 HTML/CSS 中实际使用的字形

提取关键 CSS:

提取首屏内容所需的 CSS,并将其内联到 HTML <head> 中。其余 CSS 异步加载。

重要原因:

  • 阻塞渲染的 CSS 往往是首次内容绘制缓慢的最大原因
  • 内联关键 CSS 可消除初始视图所需的网络请求
  • 页面可交互后,再加载非关键 CSS

实现方法:

  • 使用 critical(npm 包)或 Penthouse 自动提取首屏 CSS
  • 或手动识别关键 CSS:页眉样式、主视觉布局、初始排版以及首屏组件样式
  • 将关键 CSS 内联到 <head> 中的 <style> 标签内
  • 异步加载完整样式表:
<head>
  <style>
    /* Critical CSS inlined here */
  </style>
  <link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>

注意事项:

  • 内联的 CSS 不要超过约 14KB(gzip 压缩后),以符合单次 TCP 往返的预算
  • 必须确保关键 CSS 与实际首屏内容保持同步;布局变化时要重新生成
  • 对于 SPA,可考虑按路由而非按页面提供关键 CSS

优化加载策略:

  • 优先加载关键资源(对非关键资源使用 async/defer)
  • 预加载关键资源
  • 预获取可能的下一页面
  • 使用 Service Worker 实现离线访问和缓存
  • 使用 HTTP/2 或 HTTP/3 实现多路复用

使用容器查询实现组件级响应式布局:

容器查询让组件根据自身容器的大小而非视口大小进行适配。这减少了对全页面断点覆盖规则的需求,也让组件更易复用。

适用场景:

  • 组件会出现在多个上下文中(侧边栏、主栏、模态框)
  • 组件布局应取决于可用空间,而非设备宽度
  • 希望减少页面级断点的数量

请参阅容器查询参考,了解语法、实用模式和浏览器支持情况。 性能说明:

  • 容器查询的运行时开销极小;它们像媒体查询一样在合成器上运行
  • 除非确实需要同时查询两个维度,否则优先使用 container-type: inline-size,而不是 size
  • 避免在每个元素上创建 containment 上下文;仅在组件需要查询其容器时创建
渲染性能

避免布局抖动:

// ❌ Bad: Alternating reads and writes (causes reflows)
elements.forEach(el => {
  const height = el.offsetHeight; // Read (forces layout)
  el.style.height = height * 2; // Write
});

// ✅ Good: Batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight); // All reads
elements.forEach((el, i) => {
  el.style.height = heights[i] * 2; // All writes
});

优化渲染:

  • 对独立区域使用 CSS contain 属性
  • 尽量减少 DOM 深度(结构越扁平,速度越快)
  • 减少 DOM 大小(减少元素数量)
  • 对长列表使用 content-visibility: auto
  • 对超长列表使用虚拟滚动——如果架构尚未确定,优先考虑 TanStack Virtual;如果项目已有虚拟化技术栈,则优先保留现有方案
  • 对文本密集且高度可变的列表或卡片,如果换行才是真正的瓶颈,应优先使用预测式文本测量,而不是反复实时读取 DOM 高度

减少绘制与合成:

  • 使用 transform 和 opacity 实现动画(由 GPU 加速)
  • 避免对布局属性(width、height、top、left)添加动画
  • 仅在已知操作开销较大时谨慎使用 will-change
  • 尽量缩小绘制区域(越小越快)
动画性能

GPU 加速:

/* ✅ GPU-accelerated (fast) */
.animated {
  transform: translateX(100px);
  opacity: 0.5;
}

/* ❌ CPU-bound (slow) */
.animated {
  left: 100px;
  width: 300px;
}

流畅达到 60fps:

  • 目标是每帧 16ms(60fps)
  • 对 JS 动画使用 requestAnimationFrame
  • 对滚动处理程序进行防抖或节流
  • 尽可能使用 CSS 动画
  • 避免在动画期间运行长时间的 JavaScript

Intersection Observer:

// Efficiently detect when elements enter viewport
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Element is visible, lazy load or animate
    }
  });
});
React/框架优化

React 专项:

  • 对开销较大的组件使用 memo()
  • 对开销较大的计算使用 useMemo() 和 useCallback()
  • 对长列表进行虚拟化
  • 对路由进行代码拆分
  • 避免在渲染时创建内联函数
  • 使用 React DevTools Profiler

与框架无关:

  • 尽量减少重复渲染
  • 对开销较大的操作进行防抖
  • 对计算结果进行记忆化
  • 延迟加载路由和组件
网络优化

减少请求:

  • 合并较小的文件
  • 使用 SVG 精灵图存放图标
  • 内联较小的关键资源
  • 移除未使用的第三方脚本

优化 API:

  • 使用分页(不要一次加载所有内容)
  • 使用 GraphQL 仅请求所需字段
  • 压缩响应(gzip、brotli)
  • 设置 HTTP 缓存标头
  • 使用 CDN 提供静态资源

针对慢速连接进行优化:

  • 根据连接情况进行自适应加载(navigator.connection)
  • 使用乐观 UI 更新
  • 对请求进行优先级排序
  • 逐步增强

核心 Web 指标优化

最大内容绘制 (LCP < 2.5s)
  • 优化首屏主视觉图片
  • 内联关键 CSS
  • 预加载关键资源
  • 使用 CDN
  • 使用服务器端渲染
首次输入延迟 (FID < 100ms) / INP (< 200ms)
  • 拆分长任务
  • 延迟加载非关键 JavaScript
  • 使用 Web Worker 进行繁重计算
  • 减少 JavaScript 执行时间
累积布局偏移 (CLS < 0.1)
  • 为图片和视频设置尺寸
  • 不要在现有内容上方插入内容
  • 使用 CSS aspect-ratio 属性
  • 为广告/嵌入内容预留空间
  • 避免导致布局偏移的动画
/* Reserve space for image */
.image-container {
  aspect-ratio: 16 / 9;
}

性能监控

可使用的工具:

  • Chrome DevTools(Lighthouse、Performance 面板)
  • WebPageTest
  • Core Web Vitals(Chrome UX Report)
  • 打包分析工具(webpack-bundle-analyzer)
  • 性能监控工具(Sentry、DataDog、New Relic)

关键指标:

  • LCP、FID/INP、CLS(Core Web Vitals)
  • 可交互时间(TTI)
  • 首次内容绘制(FCP)
  • 总阻塞时间(TBT)
  • 打包体积
  • 请求数量

重要:在真实设备和真实网络条件下进行测量。使用高速网络的桌面版 Chrome 无法代表实际情况。

切勿:

  • 未经测量就进行优化(过早优化)
  • 为了性能牺牲无障碍性
  • 在优化过程中破坏功能
  • 到处使用 will-change(这会创建新图层并占用内存)
  • 对首屏内容进行延迟加载
  • 忽视重大问题,转而优化微小细节(优先优化最大的瓶颈)
  • 忽视受限浏览器环境下的性能(此类环境通常硬件较慢、CPU 预算更紧张、网络连接更慢)

验证改进效果

测试优化是否有效:

  • 优化前后指标:比较 Lighthouse 得分
  • 真实用户监控:跟踪真实用户的体验改进
  • 不同设备:在低功耗触控设备和主流笔记本电脑/桌面浏览器上测试
  • 慢速连接:将网络限速至 3G,测试使用体验
  • 无回归问题:确保功能仍然正常
  • 用户感知:使用起来是否感觉更快?

请记住:性能是一项功能。快速的体验会让人觉得响应更灵敏、更完善、更专业。系统地进行优化,严格地进行测量,并优先提升用户感知到的性能。

评论

支持 Markdown