Visual regression testing. Catching unintended CSS and layout changes with screenshot comparisons. The goal is confidence when refactoring, not a CI job that everyone ignores because it flakes every Tuesday.
What visual regression tests do
A tool renders pages (or components) in a headless browser, captures screenshots, and diffs them against approved baselines. Pixel differences above a threshold fail the build. You review whether the change is intentional, then update baselines or fix the CSS.
Lightweight tooling options
- Playwright –
toHaveScreenshot()built in; good for a handful of key pages. - BackstopJS – scenario-based; suits static marketing sites.
- Chromatic / Percy – hosted review UI; costs money, saves setup time.
- Storybook + test runner – component-level captures before full-page tests.
Start small. Three to five critical views beat two hundred pages nobody maintains.
What to snapshot
- Homepage hero and navigation at mobile and desktop widths.
- One representative form with focus and error states.
- Dashboard or data-heavy layout if you ship one.
- Dark mode variant if theming is a product feature.
Component Storybook stories for buttons, cards, and alerts catch regressions before they reach full pages.
Reducing flake
Flaky visual tests erode trust fast. Stabilise renders:
/* disable animations in test mode */
[data-test-stable] *,
[data-test-stable] *::before,
[data-test-stable] *::after {
animation: none !important;
transition: none !important;
}
/* fixed dimensions for dynamic charts in snapshots */
.chart-fixture {
width: 400px;
height: 240px;
}
- Wait for fonts with
document.fonts.ready. - Stub dates and random IDs in test fixtures.
- Use a consistent device scale and timezone in CI.
- Set a sensible diff threshold (1-2%) for anti-aliasing variance.
Workflow
- PR opens – CI runs visual diff.
- Failures attach comparison images to the PR.
- Reviewer approves intentional changes; baselines update in the same PR.
- Unintentional diffs send the author back to the CSS.
What visual tests do not replace
They do not verify accessibility, keyboard flows, or business logic. Pair with a few interaction tests and manual axe checks. Visual regression catches ‘the button moved sixteen pixels’; it does not catch ‘the button is unreachable by keyboard’.
The final tutorial is a mini project: a themeable component library with a CSS-only API – tokens, layers, and components you could drop into a real project.

