screenshot
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseScreenshot-Based UI Verification
基于截图的UI视觉验证
Visual verification workflow for UI changes to accelerate code review and catch responsive design issues early.
针对UI变更的视觉验证工作流,用于加速代码评审并提前发现响应式设计问题。
When to Use This Skill
何时使用该Skill
Use this skill when:
- Making any UI changes (components, styling, layout)
- Implementing responsive design
- Creating pull requests with visual changes
- Want to demonstrate UI behavior without reviewers running code locally
- Need to document visual state before/after bug fixes
在以下场景使用此Skill:
- 进行任何UI变更(组件、样式、布局)时
- 实现响应式设计时
- 创建包含视觉变更的拉取请求(PR)时
- 希望无需评审人员本地运行代码即可展示UI行为时
- 需要记录Bug修复前后的视觉状态时
Why Screenshot Verification Matters
为什么截图验证很重要
Benefits
优势
- Faster Reviews: Reviewers see changes instantly without local setup
- Documents Design: Creates visual record of design decisions
- Visual Changelog: Historical record of UI evolution
- Catches Responsive Issues: Early detection of mobile/tablet problems
- Reduces Communication: Less back-and-forth about visual changes
- Quality Gate: Forces conscious review of visual output
- 更快的评审速度:评审人员无需本地搭建环境即可立即查看变更
- 设计文档化:创建设计决策的视觉记录
- 视觉变更日志:UI演进的历史记录
- 提前发现响应式问题:尽早检测移动端/平板端问题
- 减少沟通成本:减少关于视觉变更的来回沟通
- 质量关卡:强制对视觉输出进行有意识的评审
Problems It Solves
解决的问题
- ❌ "I can't reproduce the layout issue locally"
- ❌ "What does this look like on mobile?"
- ❌ "Is this the intended design?"
- ❌ "How does this compare to the old version?"
- ✅ All answered with screenshots in PR
- ❌ "我无法在本地复现布局问题"
- ❌ "这在移动端是什么样子?"
- ❌ "这是预期的设计吗?"
- ❌ "这和旧版本相比有什么变化?"
- ✅ 所有问题都可通过PR中的截图得到解答
Required Screenshots
所需截图
For any PR that changes UI, capture all three viewport sizes:
对于任何包含UI变更的PR,需捕获以下三种视口尺寸的截图:
1. Desktop View (1920x1080)
1. 桌面端视图(1920x1080)
- Full page screenshot
- Key component close-ups if needed
- Before and after comparisons (for fixes/refactors)
- Different states (default, hover, active, error, loading)
- 全页面截图
- 必要时添加关键组件特写
- Bug修复/重构前后的对比图
- 不同状态(默认、悬停、激活、错误、加载)
2. Tablet View (768x1024)
2. 平板端视图(768x1024)
- Portrait orientation
- Verify responsive breakpoints
- Touch interaction targets visible
- Menu/navigation in tablet mode
- 竖屏方向
- 验证响应式断点
- 触控交互目标可见
- 平板模式下的菜单/导航
3. Mobile View (375x667)
3. 移动端视图(375x667)
- Portrait orientation (iPhone 8/SE size - common minimum)
- Touch target sizes visible (minimum 44x44px)
- Scrolling behavior documented
- Mobile menu states
- 竖屏方向(iPhone 8/SE尺寸 - 常见最小规格)
- 触控目标尺寸可见(最小44x44px)
- 记录滚动行为
- 移动端菜单状态
How to Capture Screenshots
如何捕获截图
Browser DevTools Method
浏览器开发者工具方法
Chrome/Edge DevTools:
- Open DevTools (F12 or Cmd+Option+I)
- Toggle device toolbar (Cmd+Shift+M or Ctrl+Shift+M)
- Select device preset or custom dimensions:
- Desktop: 1920 x 1080
- Tablet: 768 x 1024
- Mobile: 375 x 667
- Capture screenshot:
- Full page: Cmd+Shift+P → "Capture full size screenshot"
- Viewport only: Cmd+Shift+P → "Capture screenshot"
Firefox DevTools:
- Open DevTools (F12)
- Toggle Responsive Design Mode (Cmd+Option+M)
- Set dimensions
- Click screenshot icon in toolbar
Chrome/Edge DevTools:
- 打开开发者工具(F12 或 Cmd+Option+I)
- 切换设备工具栏(Cmd+Shift+M 或 Ctrl+Shift+M)
- 选择设备预设或自定义尺寸:
- 桌面端:1920 x 1080
- 平板端:768 x 1024
- 移动端:375 x 667
- 捕获截图:
- 全页面:Cmd+Shift+P → "捕获完整尺寸截图"
- 仅视口:Cmd+Shift+P → "捕获截图"
Firefox DevTools:
- 打开开发者工具(F12)
- 切换响应式设计模式(Cmd+Option+M)
- 设置尺寸
- 点击工具栏中的截图图标
CLI Screenshot Tools
命令行截图工具
Using Playwright (recommended for CI):
javascript
// screenshot.js
const { chromium } = require('playwright');
async function captureScreenshots(url) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
// Desktop
await page.setViewportSize({ width: 1920, height: 1080 });
await page.screenshot({
path: 'screenshots/desktop.png',
fullPage: true
});
// Tablet
await page.setViewportSize({ width: 768, height: 1024 });
await page.screenshot({
path: 'screenshots/tablet.png',
fullPage: true
});
// Mobile
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({
path: 'screenshots/mobile.png',
fullPage: true
});
await browser.close();
}
captureScreenshots('http://localhost:3000');Run:
node screenshot.jsUsing Puppeteer:
javascript
// screenshot.js
const puppeteer = require('puppeteer');
async function captureScreenshots(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
// Desktop
await page.setViewport({ width: 1920, height: 1080 });
await page.screenshot({
path: 'screenshots/desktop.png',
fullPage: true
});
// Tablet
await page.setViewport({ width: 768, height: 1024 });
await page.screenshot({
path: 'screenshots/tablet.png',
fullPage: true
});
// Mobile
await page.setViewport({ width: 375, height: 667 });
await page.screenshot({
path: 'screenshots/mobile.png',
fullPage: true
});
await browser.close();
}
captureScreenshots('http://localhost:3000');使用Playwright(CI环境推荐):
javascript
// screenshot.js
const { chromium } = require('playwright');
async function captureScreenshots(url) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
// Desktop
await page.setViewportSize({ width: 1920, height: 1080 });
await page.screenshot({
path: 'screenshots/desktop.png',
fullPage: true
});
// Tablet
await page.setViewportSize({ width: 768, height: 1024 });
await page.screenshot({
path: 'screenshots/tablet.png',
fullPage: true
});
// Mobile
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({
path: 'screenshots/mobile.png',
fullPage: true
});
await browser.close();
}
captureScreenshots('http://localhost:3000');运行:
node screenshot.js使用Puppeteer:
javascript
// screenshot.js
const puppeteer = require('puppeteer');
async function captureScreenshots(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
// Desktop
await page.setViewport({ width: 1920, height: 1080 });
await page.screenshot({
path: 'screenshots/desktop.png',
fullPage: true
});
// Tablet
await page.setViewport({ width: 768, height: 1024 });
await page.screenshot({
path: 'screenshots/tablet.png',
fullPage: true
});
// Mobile
await page.setViewport({ width: 375, height: 667 });
await page.screenshot({
path: 'screenshots/mobile.png',
fullPage: true
});
await browser.close();
}
captureScreenshots('http://localhost:3000');PR Description Template
PR描述模板
Use this template to document visual changes:
markdown
undefined使用以下模板记录视觉变更:
markdown
undefinedVisual Changes
视觉变更
Desktop (1920x1080)
桌面端(1920x1080)

Key changes:
- Updated header navigation layout
- Improved spacing between sections
- Added hover states to buttons

主要变更:
- 更新了头部导航布局
- 优化了区块间的间距
- 为按钮添加了悬停状态
Tablet (768x1024)
平板端(768x1024)

Key changes:
- Stacked layout for sidebar
- Touch-friendly button sizes (48x48px)
- Adjusted typography for readability

主要变更:
- 侧边栏改为堆叠布局
- 按钮尺寸适配触控(48x48px)
- 调整排版提升可读性
Mobile (375x667)
移动端(375x667)

Key changes:
- Hamburger menu replaces horizontal nav
- Single column layout
- Bottom sticky CTA button

主要变更:
- 汉堡菜单替代横向导航
- 单列布局
- 底部固定CTA按钮
Before/After Comparison
前后对比
Before (Bug)
修复前(Bug状态)

Issue: Text overflowing container on mobile

问题:移动端文本溢出容器
After (Fixed)
修复后(完成状态)

Fix: Applied word-wrap and max-width constraints

修复方案:应用自动换行和最大宽度限制
Interaction States
交互状态
Default State
默认状态


Hover State
悬停状态


Active/Selected State
激活/选中状态


Error State
错误状态


Loading State
加载状态


Responsive Design Notes
响应式设计说明
- Breakpoints: 768px (tablet), 375px (mobile)
- All touch targets > 44x44px
- Text remains readable at all sizes (min 16px body)
- No horizontal scrolling on any viewport
- Images scale proportionally
- 断点:768px(平板端)、375px(移动端)
- 所有触控目标尺寸>44x44px
- 所有尺寸下文本保持可读(正文字号最小16px)
- 所有视口无横向滚动
- 图片按比例缩放
Accessibility Checks
可访问性检查
- Keyboard navigation works
- Focus states visible
- Color contrast meets WCAG AA (4.5:1)
- Alt text on images
- ARIA labels where needed
undefined- 键盘导航正常工作
- 焦点状态可见
- 颜色对比度符合WCAG AA标准(4.5:1)
- 图片包含替代文本
- 必要时添加ARIA标签
undefinedAutomated Screenshot Testing
自动化截图测试
Using Playwright Test
使用Playwright Test
javascript
// tests/visual.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Visual Regression', () => {
test('homepage looks correct on desktop', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.setViewportSize({ width: 1920, height: 1080 });
await expect(page).toHaveScreenshot('homepage-desktop.png');
});
test('homepage looks correct on mobile', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.setViewportSize({ width: 375, height: 667 });
await expect(page).toHaveScreenshot('homepage-mobile.png');
});
});Run: (first time to generate baselines)
npx playwright test --update-snapshotsjavascript
// tests/visual.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Visual Regression', () => {
test('homepage looks correct on desktop', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.setViewportSize({ width: 1920, height: 1080 });
await expect(page).toHaveScreenshot('homepage-desktop.png');
});
test('homepage looks correct on mobile', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.setViewportSize({ width: 375, height: 667 });
await expect(page).toHaveScreenshot('homepage-mobile.png');
});
});运行:(首次运行生成基准截图)
npx playwright test --update-snapshotsUsing Storybook + Chromatic
使用Storybook + Chromatic
For component-level visual testing:
- Setup Storybook:
javascript
// Button.stories.jsx
export default {
title: 'Components/Button',
component: Button,
};
export const Primary = () => <Button variant="primary">Click me</Button>;
export const Secondary = () => <Button variant="secondary">Click me</Button>;- Integrate Chromatic:
bash
npm install --save-dev chromatic
npx chromatic --project-token=<token>- CI Integration (GitHub Actions):
yaml
undefined针对组件级别的视觉测试:
- 搭建Storybook:
javascript
// Button.stories.jsx
export default {
title: 'Components/Button',
component: Button,
};
export const Primary = () => <Button variant="primary">Click me</Button>;
export const Secondary = () => <Button variant="secondary">Click me</Button>;- 集成Chromatic:
bash
npm install --save-dev chromatic
npx chromatic --project-token=<token>- CI集成(GitHub Actions):
yaml
undefined.github/workflows/chromatic.yml
.github/workflows/chromatic.yml
name: Chromatic
on: push
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx chromatic --project-token=${{ secrets.CHROMATIC_TOKEN }}
undefinedname: Chromatic
on: push
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx chromatic --project-token=${{ secrets.CHROMATIC_TOKEN }}
undefinedScreenshot Checklist
截图检查清单
Before submitting PR with UI changes:
提交包含UI变更的PR前,请检查:
Capture Requirements
捕获要求
- Desktop screenshot (1920x1080) captured
- Tablet screenshot (768x1024) captured
- Mobile screenshot (375x667) captured
- All screenshots uploaded to PR
- Before/after comparison included (for bug fixes)
- 已捕获桌面端截图(1920x1080)
- 已捕获平板端截图(768x1024)
- 已捕获移动端截图(375x667)
- 所有截图已上传至PR
- 包含前后对比图(针对Bug修复)
Quality Checks
质量检查
- Screenshots show full page (not cut off)
- No localhost URLs visible in screenshots
- No sensitive data in screenshots (PII, keys, etc.)
- Screenshots are clear and readable
- File names are descriptive (e.g., )
desktop-homepage.png
- 截图展示完整页面(无截断)
- 截图中无localhost URL
- 截图中无敏感数据(个人信息、密钥等)
- 截图清晰可读
- 文件命名具有描述性(例如:)
desktop-homepage.png
Documentation
文档记录
- Key changes listed for each viewport
- Responsive behavior described
- Accessibility notes included
- Interaction states documented (if applicable)
- 列出每个视口的主要变更
- 描述响应式行为
- 包含可访问性说明
- 记录交互状态(如适用)
Common Issues and Solutions
常见问题与解决方案
Issue: Screenshots Too Large
问题:截图文件过大
Problem: Screenshots are 5MB+ and slow to load in PR
Solution: Compress images before uploading
bash
undefined问题:截图大小超过5MB,在PR中加载缓慢
解决方案:上传前压缩图片
bash
undefinedUsing ImageMagick
使用ImageMagick
convert input.png -quality 85 output.png
convert input.png -quality 85 output.png
Using pngquant
使用pngquant
pngquant input.png --output output.png
undefinedpngquant input.png --output output.png
undefinedIssue: Dynamic Content Changes Between Screenshots
问题:截图间动态内容不一致
Problem: Timestamps, random data make screenshots inconsistent
Solution: Mock data or freeze time in tests
javascript
// Mock Date
const mockDate = new Date('2025-01-01T00:00:00Z');
jest.useFakeTimers();
jest.setSystemTime(mockDate);
// Or in Playwright
await page.addInitScript(() => {
Date.now = () => 1704067200000; // Fixed timestamp
});问题:时间戳、随机数据导致截图不一致
解决方案:模拟数据或在测试中冻结时间
javascript
// 模拟日期
const mockDate = new Date('2025-01-01T00:00:00Z');
jest.useFakeTimers();
jest.setSystemTime(mockDate);
// 或在Playwright中
await page.addInitScript(() => {
Date.now = () => 1704067200000; // 固定时间戳
});Issue: Screenshot Diffs Show Font Rendering Differences
问题:截图差异显示字体渲染不同
Problem: Same code renders differently on different OS
Solution: Use Docker for consistent environment
dockerfile
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npm", "run", "screenshot"]问题:同一代码在不同操作系统上渲染效果不同
解决方案:使用Docker保证环境一致性
dockerfile
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npm", "run", "screenshot"]Screenshot Organization
截图管理
Directory Structure
目录结构
screenshots/
├── desktop/
│ ├── homepage.png
│ ├── product-list.png
│ └── checkout.png
├── tablet/
│ ├── homepage.png
│ ├── product-list.png
│ └── checkout.png
└── mobile/
├── homepage.png
├── product-list.png
└── checkout.pngscreenshots/
├── desktop/
│ ├── homepage.png
│ ├── product-list.png
│ └── checkout.png
├── tablet/
│ ├── homepage.png
│ ├── product-list.png
│ └── checkout.png
└── mobile/
├── homepage.png
├── product-list.png
└── checkout.pngNaming Convention
命名规范
- Use descriptive names:
desktop-homepage-logged-in.png - Include state if relevant:
mobile-form-error-state.png - Version comparisons: ,
before-header-fix.pngafter-header-fix.png
- 使用描述性名称:
desktop-homepage-logged-in.png - 相关状态需包含在内:
mobile-form-error-state.png - 版本对比:,
before-header-fix.pngafter-header-fix.png
Integration with CI/CD
与CI/CD集成
GitHub Actions Example
GitHub Actions示例
yaml
name: Visual Testing
on: pull_request
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build app
run: npm run build
- name: Start app
run: npm start &
- name: Wait for app
run: npx wait-on http://localhost:3000
- name: Capture screenshots
run: node scripts/screenshot.js
- name: Upload screenshots
uses: actions/upload-artifact@v4
with:
name: screenshots
path: screenshots/yaml
name: Visual Testing
on: pull_request
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build app
run: npm run build
- name: Start app
run: npm start &
- name: Wait for app
run: npx wait-on http://localhost:3000
- name: Capture screenshots
run: node scripts/screenshot.js
- name: Upload screenshots
uses: actions/upload-artifact@v4
with:
name: screenshots
path: screenshots/Best Practices
最佳实践
Do's
建议
- ✅ Capture all three viewport sizes
- ✅ Include before/after for bug fixes
- ✅ Document interaction states (hover, active, error)
- ✅ Compress large images
- ✅ Use descriptive file names
- ✅ Annotate screenshots with key changes
- ✅ 捕获三种视口尺寸的截图
- ✅ Bug修复需包含前后对比图
- ✅ 记录交互状态(悬停、激活、错误)
- ✅ 压缩大尺寸图片
- ✅ 使用描述性文件名
- ✅ 为截图标注主要变更
Don'ts
不建议
- ❌ Skip mobile screenshots ("desktop only" is rare)
- ❌ Upload screenshots with sensitive data
- ❌ Use random viewport sizes (stick to standards)
- ❌ Forget to document responsive breakpoints
- ❌ Rely solely on screenshots (still need code review)
- ❌ 跳过移动端截图(“仅桌面端”场景极少)
- ❌ 上传包含敏感数据的截图
- ❌ 使用随机视口尺寸(遵循标准)
- ❌ 忘记记录响应式断点
- ❌ 仅依赖截图(仍需进行代码评审)
Related Skills
相关Skill
- - Pre-merge verification checklist
universal-verification-pre-merge - - Web application testing patterns
universal-testing-webapp-testing - - Playwright testing framework
toolchains-javascript-testing-playwright - - Verification workflows
universal-debugging-verification-before-completion
- - 合并前通用验证检查清单
universal-verification-pre-merge - - Web应用测试模式
universal-testing-webapp-testing - - Playwright测试框架
toolchains-javascript-testing-playwright - - 完成前验证工作流
universal-debugging-verification-before-completion