Responsive Visual Testing Across Screen Sizes
Why Single-Viewport Testing Is Insufficient
Responsive web design means that the same HTML renders differently at different screen widths, controlled by CSS media queries, flexbox wrapping, grid auto-placement, and container queries. Each of these mechanisms introduces a point where the layout changes behavior, and each is a point where a CSS modification can produce unintended results.
Consider a three-column product grid. At 1440px, three cards sit side by side. At 768px, the grid wraps to two columns with the third card below. At 375px, the cards stack vertically. A padding change in the card component might look fine at all three widths, or it might cause the third card to partially overlap the second at exactly 768px because the available width for two columns no longer accommodates the wider padding. A visual test at 1440px passes. A visual test at 375px passes. Only a test at 768px catches the regression.
Analytics data consistently shows that mobile traffic accounts for 50% to 70% of visits for most websites. Testing only at desktop width means the majority of your users are relying on untested layouts. Conversely, testing only at mobile width misses regressions on the screens where complex layouts, data tables, and multi-column content live.
Choosing the Right Viewports
The goal is not to test at every possible screen width. That would produce thousands of screenshots and make review impossible. Instead, test at the widths where your layout changes behavior, plus the most common device widths in your traffic.
Start with Your Breakpoints
Your CSS defines breakpoints where media queries activate. These are the exact widths where the layout transitions between states, and they are the widths most likely to produce visual regressions. Common breakpoint sets:
- Tailwind CSS defaults: 640px, 768px, 1024px, 1280px, 1536px
- Bootstrap defaults: 576px, 768px, 992px, 1200px, 1400px
- Custom: whatever your stylesheet uses
Test at one width just below each breakpoint and one width just above it to verify that the transition happens correctly. In practice, most teams test at the breakpoint width itself, which catches the "at the breakpoint" state. If your layouts are known to have edge-case behavior near breakpoints, testing at breakpoint minus one pixel adds precision.
The Practical Minimum Set
For most projects, three viewports provide sufficient responsive coverage with manageable review volume:
- Mobile: 375px width (iPhone SE/standard, the most common narrow viewport)
- Tablet: 768px width (iPad portrait, the most common medium viewport)
- Desktop: 1440px width (common desktop monitor, wide enough to show full layouts)
This set catches regressions at narrow, medium, and wide widths. It misses bugs that occur exclusively at uncommon widths like 480px or 1200px, but those widths produce far fewer layout changes than the three above. If your analytics show significant traffic at additional widths, add those.
When to Add More Viewports
Add a fourth or fifth viewport when your layout has a breakpoint between two of the three defaults that is known to be fragile. Common additions:
- Large mobile / small tablet (480px to 640px): for sites with complex mobile layouts that change behavior before reaching tablet width
- Large tablet / small desktop (1024px): for sites where the desktop layout activates around this width with significant structural change
- Ultra-wide (1920px or wider): for sites with max-width containers where centering, background, or edge behavior matters
Each added viewport multiplies your screenshot count and review surface. Five viewports with 50 test pages produces 250 screenshots per run. Keep the set as small as possible while covering the breakpoints that matter most for your specific layout.
Configuring Responsive Visual Tests
Playwright handles responsive testing through projects in the configuration file. Each project specifies a viewport, and all tests run at each viewport:
// playwright.config.ts
export default defineConfig({
projects: [
{
name: 'mobile',
use: { viewport: { width: 375, height: 812 } },
},
{
name: 'tablet',
use: { viewport: { width: 768, height: 1024 } },
},
{
name: 'desktop',
use: { viewport: { width: 1440, height: 900 } },
},
],
});
Each project generates separate baseline images, so a regression at mobile width only fails the mobile project. The test report clearly shows which viewport produced the failure.
BackstopJS specifies viewports in its JSON configuration. Each scenario is captured at every viewport:
{
"viewports": [
{ "label": "mobile", "width": 375, "height": 812 },
{ "label": "tablet", "width": 768, "height": 1024 },
{ "label": "desktop", "width": 1440, "height": 900 }
]
}
Percy uses width configuration per snapshot:
await percySnapshot(page, 'Homepage', {
widths: [375, 768, 1440],
});
Percy counts each width as a separate snapshot for billing, so responsive testing triples the snapshot cost compared to single-width testing.
Mobile-Specific Testing Challenges
Setting a viewport width to 375px in a headless desktop browser is not the same as rendering on an actual mobile device. Several differences can produce misleading results:
Font rendering. Mobile browsers render fonts with different hinting and anti-aliasing than desktop browsers at the same width. A baseline captured in desktop Chromium at 375px will have minor font rendering differences compared to actual mobile Safari or mobile Chrome.
Touch target sizing. Mobile interfaces need minimum touch target sizes (48x48 CSS pixels per Google's guidelines). A visual test at 375px viewport width does not validate touch target sizing unless you explicitly assert on element dimensions.
Scroll behavior. Mobile browsers handle overflow, position:fixed, and viewport units (vh, dvh) differently from desktop browsers. A component that works perfectly in desktop Chromium at 375px can break on real mobile Safari because of address bar height changes or different overflow scrolling behavior.
Device pixel ratio. Mobile devices typically have 2x or 3x pixel density. Screenshots at 375px CSS width on a 2x device produce 750px actual pixel images. Playwright supports setting deviceScaleFactor in project configuration to match real device pixel density, which produces higher-resolution screenshots but also means baselines from 1x and 2x renders are not comparable.
For most projects, desktop browser at mobile viewport width catches the majority of responsive layout bugs (flexbox wrapping, grid behavior, media query activation, overflow) at low cost. Full mobile device testing through cloud services like BrowserStack's device farm or real device labs provides higher fidelity but at significantly higher cost and complexity. Choose based on your audience: a mobile-first product with 70% mobile traffic justifies real device testing. A B2B dashboard with 90% desktop traffic does not.
Cross-Browser Responsive Testing
Different browser engines render responsive layouts with subtle differences. WebKit (Safari) handles certain flexbox edge cases differently from Chromium, and Firefox has its own CSS interpretation quirks. Cross-browser visual testing adds a browser dimension to the viewport dimension, capturing screenshots in multiple engines at each viewport size.
Playwright supports Chromium, Firefox, and WebKit natively, making cross-browser responsive testing straightforward to configure. Each combination of browser and viewport becomes a separate project with its own baselines:
projects: [
{ name: 'mobile-chromium', use: { browserName: 'chromium', viewport: { width: 375, height: 812 } } },
{ name: 'mobile-webkit', use: { browserName: 'webkit', viewport: { width: 375, height: 812 } } },
{ name: 'desktop-chromium', use: { browserName: 'chromium', viewport: { width: 1440, height: 900 } } },
{ name: 'desktop-firefox', use: { browserName: 'firefox', viewport: { width: 1440, height: 900 } } },
]
The multiplication effect is significant: 3 viewports times 3 browsers equals 9 projects, and 50 test pages produces 450 screenshots per run. Most teams find that testing Chromium at all viewports plus one or two additional browsers at one or two viewports provides sufficient cross-browser responsive coverage without overwhelming the review process.
For dedicated cross-browser testing strategy beyond visual regression, see our browser testing guide.
Reducing Review Overhead
Responsive visual testing multiplies the number of screenshots, and more screenshots means more review time when changes occur. Several strategies keep the overhead manageable:
Group changes by component, not by viewport. When a component changes, all viewports showing that component will have diffs. Reviewing the component change once, then bulk-approving all viewport variations, is faster than reviewing each viewport independently.
Use component-level testing where possible. Testing a card component in isolation at three viewports produces three screenshots. Testing ten pages that each contain the card at three viewports produces thirty. If the card changed, reviewing three component screenshots is faster than reviewing thirty page screenshots where the card change is one small part of a larger page.
Auto-approve changes in non-critical viewports. If your mobile viewport is the most important and desktop is secondary, consider configuring desktop visual tests as warnings rather than blocking failures. This lets the team focus review energy on the viewports that matter most to users.
Limit full-suite responsive runs to merge-to-main. On feature branch PRs, run visual tests at the primary viewport only. When the branch merges to main, run the full responsive suite. This catches responsive regressions before release while keeping PR feedback fast.
Test at three viewport widths minimum: mobile (375px), tablet (768px), and desktop (1440px). Each additional viewport catches bugs the others miss, but also adds review cost. Match your viewport set to your CSS breakpoints and your traffic distribution, and resist testing at widths where your layout does not change behavior.