Responsive + Performance
When to use: Before launch. After major changes. Monthly audits. When users report "it's slow" or "it looks broken on my phone."
The test: Load the page on 3G throttling at 375px wide. Still usable? Still fast?
Responsive Design
Breakpoint Testing
Test at these four widths. No exceptions.
| Breakpoint | Width | What to Check |
|---|---|---|
| Mobile | 375px | Primary content visible, CTA reachable by thumb, no horizontal scroll |
| Tablet | 768px | Layout adapts (not just squeezed desktop), navigation usable |
| Laptop | 1024px | Content fills space without stretching, grid aligns |
| Desktop | 1440px | Max-width containers prevent ultra-wide text lines |
Responsive Checklist
| Check | Threshold | How to Measure |
|---|---|---|
| No horizontal overflow | Zero horizontal scrollbar at any breakpoint | Resize browser, check for scrollbar |
| Touch targets | 44x44px minimum on mobile and tablet | DevTools: inspect element dimensions |
| Font scaling | Body text 16px minimum at every breakpoint | DevTools: computed font-size |
| Image scaling | width and height attributes set, CSS object-fit used | DevTools: verify attributes present and computed aspect ratio unchanged |
| CLS on resize | Under 0.1 when viewport changes | Lighthouse or Web Vitals extension |
| Reflow at 400% | Content accessible at 400% zoom without horizontal scroll | Browser zoom to 400%, check layout |
Mobile-Specific Checks
- Hero answers what/who/what-to-do on small screen
- CTA visible early without scrolling
- Navigation doesn't block primary content
- Thumb zone respected (primary actions bottom half of screen)
- No hover-dependent functionality (mobile has no hover)
- Text inputs don't zoom the viewport (font-size 16px minimum on inputs)
Tablet-Specific Checks
- Layout is not just a scaled-down desktop
- Multi-column content adapts to 2-column or single-column
- Modals don't cover entire screen (use drawers or full pages instead)
Core Web Vitals
These are the metrics Google uses for ranking and the thresholds users notice.
| Metric | Good | Needs Work | Poor | How to Measure |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Under 2.5s | 2.5-4.0s | Over 4.0s | Lighthouse, PageSpeed Insights |
| INP (Interaction to Next Paint) | Under 200ms | 200-500ms | Over 500ms | Chrome Web Vitals extension |
| CLS (Cumulative Layout Shift) | Under 0.1 | 0.1-0.25 | Over 0.25 | Lighthouse, Web Vitals extension |
LCP Optimization
| Problem | Solution | Expected Impact |
|---|---|---|
| Large hero image | Compress to WebP/AVIF, add width/height, use fetchpriority="high" | 500ms-2s improvement |
| Render-blocking CSS | Inline critical CSS, defer non-critical | 200ms-1s improvement |
| Slow server response | CDN, caching headers, edge rendering | 100ms-500ms improvement |
| Web fonts blocking render | font-display: swap, preload key fonts | 100ms-500ms improvement |
INP Optimization
| Problem | Solution | Expected Impact |
|---|---|---|
| Heavy JavaScript on interaction | Code-split, defer non-critical JS | 50-200ms improvement |
| Long event handlers | Break into smaller tasks with requestIdleCallback | 50-100ms improvement |
| Third-party scripts blocking main thread | Load async, defer, or lazy-load | 100-300ms improvement |
CLS Prevention
| Problem | Solution |
|---|---|
| Images without dimensions | Always set width and height attributes |
| Dynamic content injected above viewport | Reserve space with min-height or aspect-ratio |
| Web fonts causing layout shift | Use font-display: optional or size-adjust |
| Ads or embeds resizing | Set fixed dimensions on containers |
Page Weight Budget
| Resource | Budget | How to Measure |
|---|---|---|
| Total page weight | Under 1MB | DevTools: Network tab, total transferred |
| JavaScript | Under 300KB transferred | DevTools: filter by JS, check transferred size |
| CSS | Under 100KB transferred | DevTools: filter by CSS |
| Images total | Under 500KB | DevTools: filter by Img |
| Fonts | Under 100KB | DevTools: filter by Font |
| Largest single image | Under 200KB | DevTools: sort by size |
Image Optimization
| Format | Use When | Typical Savings |
|---|---|---|
| WebP | Photographs, complex images | 25-35% smaller than JPEG |
| AVIF | When browser support sufficient | 40-50% smaller than JPEG |
| SVG | Icons, logos, simple illustrations | Resolution-independent |
| Check | Threshold | How to Measure |
|---|---|---|
| Format | WebP or AVIF for photos, SVG for icons | Check file extensions |
| Responsive images | srcset with multiple sizes | Inspect <img> attributes |
| Lazy loading | Below-fold images use loading="lazy" | Inspect <img> attributes |
| Dimensions set | width and height on all <img> | DOM audit |
| Compression | Under 80% quality for JPEG/WebP | Image analysis tool |
Script Performance
- Critical JS inlined or preloaded
- Non-critical JS deferred with
deferattribute - No render-blocking scripts in
<head>withoutasync/defer - Third-party scripts loaded async
- Bundle size tracked in CI (alert on 10%+ increase)
Font Loading
-
font-display: swaporoptionalon all@font-face - Key fonts preloaded:
<link rel="preload" as="font"> - Maximum 2-3 font files loaded
- Subset fonts to required character ranges
- WOFF2 format used (best compression)
Testing Tools
| Tool | What It Measures | When to Use |
|---|---|---|
| Lighthouse | Performance, accessibility, SEO, best practices | Every deploy |
| PageSpeed Insights | Real user data + lab data | Monthly |
| WebPageTest | Detailed waterfall, filmstrip, network analysis | Debugging specific issues |
| Chrome Web Vitals Extension | Real-time CWV while browsing | During development |
| axe DevTools | Accessibility violations | Every deploy |
Manual Testing
| Test | How | What to Check |
|---|---|---|
| Keyboard only | Unplug mouse, navigate with Tab/Enter/Space | All actions reachable, focus visible |
| Screen reader | VoiceOver (Mac) or NVDA (Windows) | Page makes sense read aloud |
| Color blindness | Chrome DevTools > Rendering > Emulate vision deficiency | Information not lost |
| Slow connection | Chrome DevTools > Network > Slow 3G | Page usable within 5 seconds |
| Real device | Load on actual phone, not just DevTools emulation | Touch targets, font sizes, scroll behavior |
Monitoring
- Core Web Vitals tracked in Search Console
- Real User Monitoring (RUM) enabled (Vercel Analytics, Cloudflare, or similar)
- Performance budget in CI (alert on 10%+ regression)
- Error rate monitoring active
Automated Test
const { test, expect } = require("@playwright/test");
const AxeBuilder = require("@axe-core/playwright").default;
test("Performance and accessibility", async ({ page }) => {
await page.goto("/");
// Accessibility audit
const axeResults = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21aa"])
.analyze();
expect(axeResults.violations).toEqual([]);
// No horizontal overflow
const hasOverflow = await page.evaluate(() => {
return document.documentElement.scrollWidth > document.documentElement.clientWidth;
});
expect(hasOverflow).toBe(false);
});
Quick Diagnosis
| Symptom | Likely Cause | Fix |
|---|---|---|
| Page feels slow | Large uncompressed images | Compress, use WebP, add dimensions |
| Layout jumps on load | Missing image dimensions or dynamic content | Set width/height, reserve space |
| Mobile layout broken | No responsive breakpoints | Add media queries or responsive grid |
| Text unreadable on mobile | Font too small | Set minimum 16px, check computed sizes |
| Slow on repeat visits | No caching headers | Add Cache-Control headers |
| High CLS score | Fonts loading late, ads injecting | Use font-display: swap, fix container sizes |
| Can't tap buttons on mobile | Touch targets too small | Increase to 44x44px minimum with 8px clearance |
Context
- Visual Design -- Design standards that responsive must maintain
- Interaction + Accessibility -- Keyboard and screen reader testing
- Rendering Verification -- Verify it renders before measuring performance