preview.
Targets at a glance
| Metric | Target |
|---|---|
| Lighthouse Performance | 95+ |
| Lighthouse Accessibility | 90+ |
| Lighthouse Best Practices | 90+ |
| Lighthouse SEO | 90+ |
| Cumulative Layout Shift (CLS) | < 0.05 |
| Total Blocking Time (TBT) | ~0 ms |
| JS payload | < 5KB minified |
| CSS payload | < 15KB after Tailwind purge |
Why the targets are achievable
The production architecture is designed from first principles to eliminate the main sources of web performance overhead.Zero framework runtime
No React, Vue, Svelte, or other JavaScript framework ships to the browser for public pages. All UI is rendered to static HTML at build time by Astro’s SSG pipeline. The only JavaScript on production pages is small vanilla handlers using data-attribute event delegation — each under 50 lines. Impact: Total Blocking Time stays at or near 0 ms. The browser has no framework to parse, compile, or execute before the page becomes interactive.Static HTML from CDN edge
output: "static" in astro.config.mjs pre-renders every public page at build time. Cloudflare Pages serves these files directly from the edge CDN node nearest to the visitor — no origin server round-trip, no server-side rendering latency for public routes.
Impact: First Contentful Paint (FCP) and Largest Contentful Paint (LCP) are fast even on throttled 4G connections, because the HTML is already at the edge.
Tailwind CSS purge
Tailwind v4 uses a CSS-first configuration (@import "tailwindcss" in global.css, no tailwind.config.mjs). At build time, only the utility classes actually referenced in .astro component templates survive — all other classes are tree-shaken.
Impact: CSS payload stays under 15KB in production. No runtime style injection, no FOUC.
No layout shift
All images include explicitwidth and height attributes. Sanity’s image pipeline provides Low Quality Image Placeholders (LQIP) for above-the-fold images, which reserve space before the full image loads.
Impact: Cumulative Layout Shift (CLS) < 0.05.
Detailed targets
Lighthouse Performance (95+)
Lighthouse Performance is a weighted composite of:| Metric | Weight | Target |
|---|---|---|
| First Contentful Paint | 10% | Fast |
| Largest Contentful Paint | 25% | Fast |
| Total Blocking Time | 30% | ~0ms |
| Cumulative Layout Shift | 15% | < 0.05 |
| Speed Index | 10% | Fast |
| Interaction to Next Paint | 10% | Fast |
Lighthouse Accessibility (90+)
Accessibility is tested with axe-core in the Playwright E2E suite (WCAG 2.1 AA) and validated by Lighthouse in CI. Requirements:- All images have descriptive
alttext - Color contrast ratios meet WCAG AA minimums
- Interactive elements are keyboard-navigable
- ARIA roles are used correctly
- Form fields have associated labels
- Heading hierarchy is logical (
h1→h2→h3)
CLS < 0.05
Cumulative Layout Shift measures visual instability — elements shifting position after initial render. Common causes:Images without dimensions
Browsers cannot reserve space for images without known dimensions. Always specify
width and height on <img> elements, or use Astro’s <Image> component which infers dimensions automatically.Web font swap
Font loading with
font-display: swap can cause text to reflow. Use font-display: optional for decorative fonts or preload critical fonts.Late-injected content
Ads, embeds, or dynamically injected banners that shift layout after paint. Avoid dynamically inserting content above existing content.
LQIP placeholders
Sanity’s image pipeline generates Low Quality Image Placeholders. Use them for above-the-fold images to reserve space while the full image loads.
JS payload < 5KB
The 5KB budget covers all JavaScript shipped to production browsers — after minification and compression. What ships:- Vanilla JS event handlers for interactive elements (FAQ accordion, carousel, contact form)
- Each handler uses data-attribute event delegation, not per-element listeners
- No hydration runtime, no component tree, no virtual DOM
- Astro component JavaScript (runs at build time only)
- React (used only for Sanity Visual Editing, which is OFF in production)
- Any npm package not explicitly imported in a
<script>tag
CSS payload < 15KB
Tailwind v4’s tree-shaking typically produces 8–12KB of CSS for a site of this size. The 15KB budget includes:- Tailwind utility classes (only used ones)
- CSS custom properties (design tokens in
global.css) @keyframesanimations- Third-party CSS (iconify, etc.) if any
- Unused Tailwind utilities
- Unused CSS from npm packages
- Runtime-injected styles
Optimization checklist
Before opening a PR, verify:- No new npm packages with large client-side bundles (check
importstatements in<script>tags) - New images use Astro’s
<Image>component or have explicitwidth/height - New interactive components use data-attribute event delegation, not per-element
addEventListenercalls - No
font-display: swapfor critical text fonts - New blocks do not inject content above the fold dynamically after paint
- Run
npm run build --workspace=astro-app && npx lhci autorunlocally before pushing
Monitoring in production
Lighthouse CI runs on PRs but not on production deployments. Monitor production performance via:- Google Search Console — Core Web Vitals report (field data from real users)
- Cloudflare Analytics — Page load times by geography
- GA4 —
web_vitalsevents if configured in GTM
fix: or perf: PR with the fix targeting preview first.