Achieving 95+ Lighthouse Score on an Astro Blog
Image optimization, font subsetting, prefetching, and bundle analysis — our full performance checklist.
The 95+ Lighthouse Target
A Lighthouse score of 95+ across all four categories (Performance, Accessibility, Best Practices, SEO) is achievable with Astro — but it requires deliberate choices at every layer of the stack.
Here is the full Tsubaki checklist.
Performance
Image Optimization
Use Astro’s built-in <Image /> component for every image. It automatically:
- Generates WebP and AVIF variants.
- Adds correct
widthandheightto prevent layout shift. - Applies
loading="lazy"by default (useloading="eager"for above-the-fold images only).
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Image
src={heroImage}
alt="Hero image"
width={1200}
height={630}
loading="eager"
fetchpriority="high"
/>
Font Loading
Render-blocking fonts are the single most common cause of poor Lighthouse scores. The correct pattern:
<!-- 1. Preconnect to font CDN. -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- 2. Preload the font CSS resource. -->
<link rel="preload" as="style"
href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&display=swap" />
<!-- 3. Load non-blocking using media swap trick. -->
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&display=swap"
media="print"
onload="this.media='all'"
/>
<!-- 4. Fallback for no-JS environments. -->
<noscript>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&display=swap" />
</noscript>
The display=swap parameter in the URL enables font-display: swap, preventing invisible text during font load.
JavaScript Bundle Strategy
- No framework JavaScript by default — Astro ships zero runtime.
- GSAP is loaded via dynamic
import()— not in the initial bundle. - Use
prefetch: { prefetchAll: true, defaultStrategy: 'hover' }inastro.config.mjsto preload pages on hover, before click.
Core Web Vitals
| Metric | Target | Tsubaki Strategy |
|---|---|---|
| LCP | < 2.5s | Preload hero image, fetchpriority="high" |
| FID/INP | < 100ms | No long tasks, GSAP RAF-based |
| CLS | < 0.1 | Explicit width/height on all images |
| TTFB | < 200ms | Static HTML from edge CDN |
Accessibility
Semantic HTML
- Use proper heading hierarchy (h1 → h2 → h3, never skip).
- All interactive elements have accessible labels (
aria-labelor visible text). - Images have descriptive
alttext. - Links describe their destination, not just “click here”.
Keyboard Navigation
- All navigation is reachable by Tab key.
- Mobile menu has
aria-expandedandaria-controlsattributes. - Focus styles are visible (never
outline: nonewithout a replacement).
Color Contrast
| Combination | Ratio | WCAG Level |
|---|---|---|
#1a1a1a on #faf8f5 | 17.2:1 | AAA |
#6b6560 on #faf8f5 | 5.1:1 | AA |
#ffffff on #c8102e | 5.4:1 | AA |
Best Practices
- All assets served over HTTPS.
- No console errors or deprecated APIs.
- CSP headers recommended (configure at hosting layer).
rel="noopener noreferrer"on all external links.
SEO
- Unique
<title>and<meta name="description">on every page. - Canonical URLs to prevent duplicate content.
- Open Graph and Twitter Card meta tags for social sharing.
- Sitemap generated by
@astrojs/sitemap. - RSS feed for feed readers and SEO signals.
- JSON-LD structured data on blog posts (
BlogPostingschema).
Hosting Recommendations
For the best Lighthouse scores, deploy to an edge CDN with HTTP/2 support:
- Vercel — Zero-config Astro support, global edge network.
- Netlify — Built-in CDN, easy custom headers for security.
- Cloudflare Pages — Fastest TTFB, 200+ edge locations.
All three support Astro’s static output with no additional configuration.