Deriving the Support Matrix from Real Traffic, Not Opinions
Two engineers argue in standup about whether checkout needs to support Microsoft Edge. One says a cousin uses Edge; the other says nobody they know does. Neither has data. A support matrix ends that argument by turning browser policy into numbers you can point at: which browsers, which versions, which devices, what coverage level, reviewed on a schedule.
Where the numbers come from. Pull the last 90 days from analytics — in GA4 that is Reports → Tech → Browser & OS, split by major version if your implementation captures it. Web server logs or CDN logs (Cloudflare, Fastly, Akamai) work equally well once you filter known bots. What you want is the share of your sessions per browser family and major version, not global market-share headlines. Global numbers say Safari is roughly 18% and Chrome roughly 65%, but an enterprise SaaS where users sign in from managed corporate laptops can be 85% Chrome, while a consumer app in some markets leans hard on Samsung Internet or UC Browser. Your own traffic is the only defensible source.
Version policy beats version wishlists. Chrome, Edge, and Firefox ship a new major roughly every four weeks; Safari releases yearly with point releases tied to OS updates. A practical policy covers the current and previous major of every evergreen browser and demotes anything older. A threshold many teams adopt: cover every version that together accounts for at least 95% of sessions, and explicitly document the excluded remainder instead of silently ignoring it.
| Tier | Scope | Commitment |
|---|---|---|
| 1 | Versions covering ~95% of sessions | Automated regression on every PR |
| 2 | Next tier, up to ~99% | Manual exploratory pass per release |
| 3 | Long tail (old IE, stale Android WebView) | Fix on report, no proactive testing |
Test engines, not brand logos. Browsers are not independent products: Chrome, Edge, Brave, and Opera are all Chromium; Firefox is Gecko; Safari on iOS is WebKit — and until recent regulation forced alternative engines in the EU, Chrome iOS and Firefox iOS shipped WebKit too. This collapses your matrix. A flexbox bug in Chromium reproduces across four brands; an iOS bug reproduces in every iOS browser but no desktop one; Safari desktop is its own engine with its own date inputs, scroll behavior, and CSS prefixes. When a bug is engine-wide, one failing browser predicts four; when it is shell-level (Edge's IE-mode, Samsung's address bar), the brand itself is the row.
Devices. Emulators miss what matters: scroll jank, virtual keyboard overlapping a submit button, notch safe areas, and battery/thermal throttling. A workable device strategy for most teams is a cloud lab (BrowserStack, Sauce Labs, AWS Device Farm) for breadth plus one physical mid-range Android in the office — mid-range specifically, because flagship phones mask performance problems that dominate real traffic. iOS quirks (rubber-band scrolling, 16px input zoom, focus behavior) are best checked on one real iPhone or via Safari remote debugging from a Mac.
Revisit quarterly. Version shares drift as old releases fall off, so a matrix reviewed once a year is wrong most of the year. Keep the matrix as a markdown file in the repository so updating it is a pull request, reviewed alongside Exploratory Testing and Charters notes from the last release, and hand the Tier 1 rows directly to Automation Concepts and Frameworks as your automation targets.
Testing Breakpoints at 767, 768, and 769 — Not Every Pixel
A layout looks perfect at 768px in the emulator and breaks the moment a user resizes one pixel wider. The defect class is predictable: media queries are inclusive or exclusive at exactly one width, and testers who sample a single width per device never touch the boundary. Treat breakpoints the way you would treat any range in an input field — test below, at, and above the edge.
Find the breakpoints first. Open DevTools, select an element, and read its computed styles while dragging the viewport width — or search the CSS for @media. Typical stacks: 576, 768, 992, 1200 (Bootstrap), or custom values like 640 and 1024 (Tailwind defaults). For each declared breakpoint N, the minimum test set is:
N-1, N, N+1 → for 768: test 767, 768, 769
plus → the extremes: 320 (smallest supported), 1920 (large desktop)
plus → orientation: landscape and portrait at the same width
Orientation matters because orientation: portrait queries and viewport height math change when a phone rotates; a hero sized by 100vh often breaks in landscape where browser chrome shrinks the visible height.
What actually breaks at each width. Mobile (< 576): fixed-width elements forcing horizontal scroll, tables without overflow containers, hero text overflowing, form inputs wider than the screen. Tablet (768–992): navigation failing to collapse into the hamburger while content already sits in a single column, creating dead space; sidebars that neither stack nor stay docked. Desktop (> 1200): max-width containers leaving huge empty margins, tooltips overflowing the right edge, modals taller than the viewport with no internal scroll.
Zoom is a viewport too. Two WCAG criteria pin this down and both make good release checks: 1.4.4 allows text resizing to 200% without loss of content, and 1.4.10 (reflow) requires two-dimensional content to work at 320 CSS px wide — the equivalent of 400% zoom on a 1280px screen — with no horizontal scrolling except for essential exceptions like tables and code. Browser zoom (Ctrl + / Cmd +) is the cheap proxy: run the page at 200% and 400% and look for clipped buttons and text overlapping images.
Where to test. DevTools device mode covers width sweeps quickly, but its DPR (device pixel ratio) and touch emulation are approximations. Use it for the N-1/N/N+1 sweep on desktop widths, then confirm mobile rows on a real device or a cloud-lab handset, because safe-area insets, notch cutouts, and on-screen keyboards do not reproduce in a desktop emulator.
Make it repeatable. Once the sweep is scripted, visual regression tooling pays off: Playwright's toHaveScreenshot() or BackstopJS can capture each breakpoint per page and fail the build on pixel deltas, turning a 15-minute manual resize ritual into a CI step. Keep baselines per viewport, not one global baseline — a single baseline at 1280 tells you nothing about 375, and screenshot tests need deterministic rendering: pin the browser version, disable animations with animations: 'disabled', and mask dynamic regions like ads or timestamps so the diff only reports layout truth. A practical split is three snapshots per key page (375, 768, 1280) on every pull request, with the full N-1/N/N+1 sweep reserved for nightly runs where flakiness costs less. The manual pass that remains is judgment work: does the layout read correctly, is the tap target reachable, does content order still make sense — exactly the exploratory questions from Exploratory Testing and Charters.
Touch, Hover, and Keyboard Are Three Different Interaction Models
A mega-menu built on :hover works flawlessly in the desktop browser and in DevTools device mode. On a real iPhone it opens on first tap, then sticks open while the user tries to tap a link underneath, and there is no way to reach items that require hovering a parent first. The bug is not CSS — it is a wrong assumption that every user points with a mouse. Hover, touch, and keyboard each have distinct semantics, distinct failure modes, and distinct test passes.
Hover. Touch devices do not have hover, but they simulate it badly: the first tap often applies :hover, which then sticks until you tap elsewhere. Menus that open on hover therefore behave erratically on tablets — they fight with click, and long lists behind hover-only triggers are unreachable. DevTools device mode will not reliably reproduce sticky hover; that check needs a real device or at least a cloud-lab handset. While testing hover, also verify that hover is an enhancement: every hover-only affordance must have a click/tap path.
Touch. Three quantitative checks catch most touch defects:
Target size Apple HIG: ≥ 44×44 pt; Material Design: ≥ 48×48 dp
Spacing adjacent targets need a gap so a stray tap does not hit the neighbor
Zoom trap inputs with font-size < 16px auto-zoom on focus in iOS Safari
The 16px rule is the classic one: a login form with 14px inputs looks fine in testing on Android (no auto-zoom) and yanks the whole viewport on iOS the moment the user focuses the username field. Also test gestures versus scroll: a horizontal carousel swiped inside a vertically scrolling page needs to win the gesture in its zone without chaining the page scroll, and touch-action: none on a container can accidentally kill scrolling for the whole section.
Keyboard. A surprising share of users — power users, screen-reader users, anyone with a broken trackpad — never touch the mouse, and keyboard support is where most web apps silently fail. The pass is simple and scriptable in intent: put the mouse down and Tab from the top of the page. Verify (1) focus order follows visual order, (2) focus is always visible — no outline: none without a :focus-visible replacement, (3) modals trap focus and close on Esc, (4) dropdown menus open with arrow keys or Enter and not hover alone, (5) no keyboard trap where focus enters a widget and cannot leave (an old iframe bug), and (6) a skip link lets keyboard users jump past the nav. Automated tools like axe or Lighthouse flag missing labels and roles, but tab order and focus traps still need the human pass — or a Playwright test that literally presses Tab in a loop.
Run the three passes deliberately. For each Tier 1 page from your matrix: a mouse pass (hover states, drag-and-drop), a touch pass on a real device (tap targets, gestures, zoom trap, safe areas), and a keyboard-only pass (order, visibility, traps). Each pass takes minutes on a focused page and catches a defect class the other two never will — which is exactly why they are separate checklists rather than one 'device test'. When an input-method defect is suspicious (works in emulator, fails on hardware), the next stop is failure classification in Debugging Failing Tests.
Quiz
1. Your analytics show Chromium-based browsers (Chrome, Edge, Brave, Opera) at 78%, Safari desktop at 9%, Safari iOS at 10%, and Firefox at 3%. How many distinct rendering engines must your team actually test?
2. Your CSS declares a breakpoint at 768px. Which set of widths constitutes the minimum boundary test?
3. A hover-only dropdown menu passes in DevTools device mode but sticks open after the first tap on a real iPad. What is the root cause?
4. During a keyboard-only pass, focus enters a modal dialog and Tab keeps moving to links behind it. What must the test verify as the fix?
Flashcards
Question
What is a browser support matrix, and what is its single source of truth?
Click to reveal answer
Answer
A table of browser families, major versions, and devices with a tiered testing commitment for each row. The source of truth is your own analytics for the last ~90 days (GA4 Browser & OS report, server/CDN logs) — not global market-share sites — because an enterprise product and a consumer app have completely different traffic mixes.
Question
Why should coverage be planned by rendering engine rather than by browser brand?
Click to reveal answer
Answer
Chrome, Edge, Brave, and Opera all ship Chromium; Firefox is Gecko; Safari desktop and iOS browsers are WebKit. Rendering bugs reproduce per engine — one Chromium failure predicts four brands — so engine-level testing collapses the matrix, while brand-level rows remain only for shell-specific features like Edge IE-mode or iOS browser chrome.
Question
What is the minimum width set for testing a breakpoint declared at N pixels?
Click to reveal answer
Answer
N-1, N, and N+1 — below, at, and above the trigger — plus the range extremes (320, 1920) and both orientations. The media query's inclusive/exclusive edge is where defects live, mirroring boundary value analysis: sampling a single width per device never touches the boundary.
Question
Name three touch-specific defects that emulators typically miss and how to check each.
Click to reveal answer
Answer
1) Sticky hover — first tap applies :hover on touch, so hover-only menus misbehave; check on a real device. 2) Auto-zoom — iOS Safari zooms any input with font-size below 16px on focus; check form styling. 3) Tap target and gesture issues — targets under 44×44pt/48×48dp and carousels fighting page scroll; measure sizes and swipe inside scrolling containers.
Question
What do WCAG 1.4.4 and 1.4.10 require for zoom, and what is the quick manual check?
Click to reveal answer
Answer
1.4.4: content remains usable at 200% text resize. 1.4.10 (reflow): two-dimensional content works at 320 CSS px wide — equivalent to 400% zoom on 1280 — with no horizontal scrolling except for essential exceptions (tables, code). Quick check: run the page at 200% and 400% browser zoom and look for clipped or overlapping content.
Revision Notes
Key Takeaways
- 1. Support matrices are decided by analytics session share with an explicit ~95% threshold, not by whoever argues loudest in standup
- 2. Bugs spread by rendering engine — three engines cover modern web rendering; brand rows only matter for shell-specific behavior
- 3. Breakpoints are boundaries: always test N-1/N/N+1, both orientations, and 200%/400% zoom because WCAG reflow fixes the 320px floor
- 4. Hover, touch, and keyboard are separate interaction models with separate defect classes; each deserves its own short pass on real input
- 5. One physical mid-range Android catches scroll and keyboard problems that emulators and flagship phones both hide
Interview Tips
- • "How do you decide which browsers to test?" — pull 90 days of analytics, tier by session share with a written threshold (say 95% for automation), document the excluded remainder; naming engines (Chromium/Gecko/WebKit) shows you compress the work intelligently
- • "A layout breaks at 768px in production but your test passed — what happened?" — you tested the middle of the range, not the boundary; the fix is the N-1/N/N+1 sweep, which is boundary value analysis applied to viewport widths
- • "How would you test a hover menu for mobile?" — first question is whether hover-only paths exist at all; touch makes :hover sticky on first tap, so demand a click/tap path and verify on a real device rather than DevTools emulation
- • "What is your device testing strategy?" — cloud lab for breadth, one physical mid-range Android for performance realism, one iPhone for iOS-specific quirks (auto-zoom, safe areas), plus keyboard-only passes that need no device at all
Cheat Sheet
Cross-Browser & Device Coverage
Build the matrix from your traffic (last 90 days):
| Tier | Scope | Commitment |
|---|---|---|
| 1 | Versions covering ~95% of sessions | Automated regression every PR |
| 2 | Up to ~99% of sessions | Manual pass per release |
| 3 | Long tail | Fix on report only |
Engines, not brands: Chromium (Chrome/Edge/Brave/Opera) · Gecko (Firefox) · WebKit (Safari desktop + iOS browsers). Test engines; spot-check shells.
Breakpoint sweep per declared N: N-1, N, N+1 + 320 + 1920 + both orientations + zoom at 200% / 400%.
Input-method passes:
- Mouse: hover is enhancement only; every hover action needs a click path
- Touch: targets ≥44×44pt (Apple) / ≥48×48dp (Material); inputs ≥16px font (iOS auto-zoom); gesture zones must not kill page scroll
- Keyboard: logical focus order, visible focus (no bare
outline:none), modal focus trap + Esc, no keyboard traps, skip link
Device strategy: cloud lab (BrowserStack / Sauce Labs / AWS Device Farm) for breadth + one physical mid-range Android (flagships mask jank) + one real iPhone for iOS quirks.
Cadence: review matrix quarterly; keep it in the repo as markdown, updated via PR.