Playwright screenshot font rendering differs across OS in CI
Text renders with different anti-aliasing, hinting, and even fallback fonts on macOS, Windows, and Linux. A baseline made on one OS will always differ from the same page rendered on another, so screenshots must be generated on the same platform CI uses.
What this error means
Screenshots pass locally on macOS but fail in CI with thousands of differing pixels concentrated around text. The -diff.png shows a faint outline of every glyph rather than a real layout change.
Error: A snapshot doesn't match its reference.
31204 pixels (ratio 0.05 of all image pixels) are different.
(differences cluster around all text; no layout change)Common causes
Baseline and runner use different font stacks
macOS and Windows ship fonts and a text renderer that differ from a Linux runner. Even identical CSS produces different pixels around every glyph edge.
The runner lacks the fonts the page requests
If the page uses a web font that is not loaded in time, or a system font missing on the runner, the browser substitutes a fallback and the text shifts.
How to fix it
Generate baselines in the official Playwright image
- Use the versioned
mcr.microsoft.com/playwrightimage both locally (to write baselines) and in CI (to compare). - Pin the same image tag in both places so the font stack is identical.
- Regenerate and commit baselines from inside that image.
# CI job runs inside the same image used to make baselines
container:
image: mcr.microsoft.com/playwright:v1.44.0-jammyInstall the exact fonts and wait for web fonts
Bundle the fonts the page needs into the image, and wait for document.fonts.ready before capturing so late web fonts do not cause a fallback render.
await page.evaluate(() => document.fonts.ready);
await expect(page).toHaveScreenshot('hero.png');How to prevent it
- Standardize on one Docker image for generating and comparing screenshots.
- Install the required fonts into the runner image.
- Wait for
document.fonts.readybefore capturing text-heavy views.