Files
astro-website/openspec/changes/lighthouse-remediation/design.md
Santhosh Janardhanan 70710239c7
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled
Theming done
2026-02-10 20:10:06 -05:00

6.0 KiB

Context

Chrome Lighthouse runs against https://santhoshj.com/ (desktop + mobile) report several audits that prevent a 100 score.

Inputs:

  • Desktop report: C:\Users\simpl\Downloads\santhoshj.com-20260210T182644.json
  • Mobile report: C:\Users\simpl\Downloads\santhoshj.com-20260210T182538.json

Key failing audits (non-exhaustive):

  • Accessibility: color-contrast
  • SEO: robots-txt, crawlable-anchors
  • Best Practices: inspector-issues (Content Security Policy)
  • Performance: render-blocking-insight, image-delivery-insight, unminified-css, unused-css-rules, unused-javascript, cache-insight (plus mobile LCP/TTI pressure)

Constraints:

  • Site is a static Astro build served behind Docker Compose + reverse proxy.
  • Some assets are third-party (YouTube thumbnails, CloudFront podcast images, Umami script). These can influence some performance/cache audits and must be handled carefully (reduce impact where possible, but avoid breaking content).
  • Service worker script MUST remain at stable URL /sw.js and should not be versioned via query string.

Goals / Non-Goals

Goals:

  • Achieve a 100 Lighthouse rating on the homepage in all categories (Performance, Accessibility, Best Practices, SEO) using the audits provided.
  • Make contrast compliant (WCAG AA) for secondary text and pill/chip labels.
  • Ensure SEO hygiene:
    • robots.txt includes a valid (absolute) sitemap URL
    • interactive elements do not render anchor tags without href.
  • Remove DevTools Issues panel findings related to CSP by implementing an explicit CSP baseline that matches site needs.
  • Reduce render-blocking requests and improve asset delivery so mobile LCP/TTI is consistently fast.

Non-Goals:

  • Redesigning the site's visual identity or typography scale.
  • Removing all third-party content sources (YouTube thumbnails, podcast cover images) or analytics.
  • Building a full PWA manifest/offline-first experience (out of scope).

Decisions

  1. Contrast remediation via token-level CSS adjustments Rationale: Lighthouse flags specific selectors in card footers and pills. Fixing contrast at the token level (e.g., --muted, pill bg/fg) avoids per-component overrides and reduces regressions. Alternatives:
  • Component-local overrides (harder to maintain, easy to miss).
  1. Robots sitemap MUST be absolute Rationale: Lighthouse treats Sitemap: /sitemap-index.xml as invalid. Robots will be updated to point at the full absolute URL. Alternatives:
  • Switch to sitemap.xml only (not desired; site already emits sitemap-index).
  1. No anchor elements without href in rendered HTML Rationale: Lighthouse flags the media modal anchors because they exist at load time without href (populated later by JS). Fix by using buttons for non-navigational actions, and ensuring any <a> is rendered with a valid href in initial HTML (or not rendered until it has one). Alternatives:
  • Keep anchors and set href="#" (still crawlable but semantically wrong, and can degrade UX).
  1. CSP baseline implemented at the edge (reverse proxy), compatible with site JS Rationale: DevTools Issues panel reports CSP issues. Implement a CSP that matches current needs (site inline scripts, Umami, fonts, images, frames) and remove/avoid inline scripts where possible to keep CSP strict. Alternatives:
  • Avoid CSP entirely (does not resolve audit and leaves security posture ambiguous).
  1. Font delivery: prefer self-hosting to remove render-blocking third-party CSS Rationale: Lighthouse render-blocking points to Google Fonts stylesheet. Self-hosting WOFF2 and using @font-face reduces blocking and improves reliability. Alternatives:
  • Keep Google Fonts and rely on preload hints (still incurs third-party CSS request; harder to reach 100).
  1. CSS delivery: move global CSS into the build pipeline (minified output) Rationale: Lighthouse flags unminified/unused CSS. Keeping global.css as a raw file in public/ makes it harder to guarantee minification/unused pruning. Prefer having Astro/Vite handle minification and (where possible) pruning. Alternatives:
  • Add a bespoke minify step for public/styles/global.css (works, but adds build complexity and can drift).
  1. Caching headers: stable URLs get revalidated; fingerprinted assets get long-lived caching Rationale: Lighthouse cache-lifetime audit penalizes short cache lifetimes on first-party CSS/JS. For assets that are not fingerprinted (e.g., /sw.js, possibly /styles/global.css), use no-cache or revalidation to avoid staleness. For fingerprinted build outputs, use long-lived caching. Alternatives:
  • Querystring versioning on SW (known pitfall; can break update chain).

Risks / Trade-offs

  • [CSP breaks site behavior] → Start with Report-Only CSP, verify in production, then enforce. Prefer eliminating inline scripts to avoid unsafe-inline.
  • [Self-hosting fonts changes appearance slightly] → Keep the same Manrope font files and weights, verify typography visually.
  • [Optimizing images reduces perceived sharpness] → Use responsive images and appropriate sizes; keep high-DPR support via srcset.
  • [Third-party cache lifetimes cannot be controlled] → Focus on first-party cache headers and reduce critical path reliance on third-party where possible.

Migration Plan

  1. Reproduce Lighthouse findings from a clean Chrome profile (no extensions) for both mobile/desktop.
  2. Apply fixes in small slices (contrast, robots/anchors, CSP, fonts, CSS pipeline/minify, image delivery).
  3. Deploy behind the reverse proxy with Report-Only CSP first.
  4. Re-run Lighthouse on production URL until 100 is reached and stable.
  5. Enable enforced CSP after confirming no violations.

Open Questions

  • What exact CSP issue is being reported in the DevTools Issues panel (violation message)? Lighthouse only surfaces the issue type without sub-items.
  • Do we want to keep Google Fonts or commit to self-hosting fonts for maximum Lighthouse consistency?
  • For cache-lifetime scoring: do we want to introduce fingerprinted CSS output (preferred) or add explicit versioning for /styles/global.css?