All skills
addyosmani avatar

/core-web-vitals

@c6b06ad official

Optimize Core Web Vitals (LCP, INP, CLS) for better page experience using field and lab evidence. Use when asked to "improve Core Web Vitals", "fix LCP", "reduce CLS", "optimize INP", "page experience optimization", or "fix layout shifts".

Use this Skill: https://skilld.dev/gh/addyosmani/web-quality-skills/core-web-vitals

This session only. Nothing lands on disk.

referencesLCP.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

LCP optimization reference

What is LCP?

Largest Contentful Paint (LCP) measures when the largest content element in the viewport becomes visible. This is typically:

  • An <img> element
  • An <image> element inside <svg>
  • A <video> element with poster image
  • An element with a background image via url()
  • A block-level element containing text nodes

LCP timeline

[  Server Response  ][  Resource Load  ][  Render  ]
       TTFB              Download         Paint
       └─────────────────────────────────────┘
                         LCP Time

Detailed optimizations

1. Server response time (TTFB)

Target: < 800ms

Causes:

  • Slow server/database queries
  • No CDN/edge caching
  • Inefficient backend code
  • Cold starts (serverless)

Solutions:

// Use edge functions for dynamic content
// Vercel example
export const config = { runtime: 'edge' };

// Use stale-while-revalidate caching
// Cache-Control header
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');

2. Resource load time

For images:

<!-- Preload only when a trace shows the LCP image is discovered late -->
<link rel="preload" as="image" href="/hero.webp" 
      imagesrcset="/hero-400.webp 400w, /hero-800.webp 800w"
      imagesizes="100vw"
      fetchpriority="high">

<!-- Modern format with fallback -->
<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img src="/hero.jpg" width="1200" height="600" 
       fetchpriority="high" alt="Hero">
</picture>

For text (web fonts):

@font-face {
  font-family: 'Heading';
  src: url('/fonts/heading.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately */
}

3. Render blocking resources

Critical CSS pattern:

<head>
  <!-- Inline critical CSS -->
  <style>
    /* Only above-fold styles, < 14KB */
    .hero { /* ... */ }
    .nav { /* ... */ }
  </style>
  
  <!-- Defer non-critical CSS -->
  <link rel="preload" href="/styles.css" as="style" 
        onload="this.onload=null;this.rel='stylesheet'">
</head>

Defer JavaScript:

<!-- ❌ Blocks parsing -->
<script src="/app.js"></script>

<!-- ✅ Deferred (runs after HTML parsed) -->
<script defer src="/app.js"></script>

<!-- ✅ Module (deferred by default) -->
<script type="module" src="/app.mjs"></script>

4. Client-side rendering

Problem: Content not in initial HTML.

Solutions:

Server-side rendering (SSR):

// Next.js
export async function getServerSideProps() {
  const data = await fetchHeroContent();
  return { props: { hero: data } };
}

Static site generation (SSG):

// Next.js
export async function getStaticProps() {
  const data = await fetchHeroContent();
  return { props: { hero: data }, revalidate: 3600 };
}

Streaming SSR:

// React 18+
import { Suspense } from 'react';

function Page() {
  return (
    <Suspense fallback={<HeroSkeleton />}>
      <Hero />
    </Suspense>
  );
}

Framework-specific tips

Next.js

import Image from 'next/image';

// LCP image with priority
<Image 
  src="/hero.jpg"
  priority
  fill
  sizes="100vw"
  alt="Hero"
/>

Nuxt

<NuxtImg
  src="/hero.jpg"
  preload
  loading="eager"
  sizes="100vw"
/>

Astro

---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<Image 
  src={hero} 
  loading="eager" 
  decoding="sync"
  alt="Hero" 
/>

Debugging LCP

// Identify LCP element
new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries();
  const lastEntry = entries[entries.length - 1];
  
  console.log('LCP:', {
    element: lastEntry.element,
    time: lastEntry.startTime,
    size: lastEntry.size,
    url: lastEntry.url,
    renderTime: lastEntry.renderTime,
    loadTime: lastEntry.loadTime
  });
}).observe({ type: 'largest-contentful-paint', buffered: true });

Common issues

Issue Evidence to confirm Typical fix
LCP resource discovered late Large resource load delay in LCPBreakdown or LCPDiscovery Put it in initial HTML, add priority, and preload only when still necessary
Large image transfer Resource load duration and response bytes dominate Resize/compress and choose an appropriate format
Render-blocking CSS RenderBlocking insight and long render delay Remove unused rules, split non-critical CSS, or inline only proven critical CSS
Slow TTFB DocumentLatency insight or LCP TTFB subpart dominates Cache, reduce redirects, or optimize server work
Client-rendered LCP LCP element absent from initial HTML and render delay dominates SSR, static rendering, or earlier rendering

Do not attach generic millisecond savings to these fixes. Measure the relevant LCP subpart before and after under equivalent conditions.

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides comprehensive and secure instructions for optimizing Core Web Vitals (LCP, INP, CLS) using industry-standard browser APIs and development frameworks. No malicious patterns, hidden code, or security risks were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    2 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at c6b06ad. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated last month
metadata
{
  "author": "web-quality-skills",
  "version": "2.0"
}
  • Performance
  • core-web-vitals
  • lcp
  • inp
  • cls
  • google-search
  • page-experience
  • web-vitals
  • optimization

README badge

README badge for addyosmani/web-quality-skills/core-web-vitals

Optimizes Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS) — the three metrics Google uses to rank page experience. Provides concrete fixes for each metric: preloading critical resources and using Speculation Rules for LCP, breaking long tasks and prioritizing visual feedback for INP, and reserving space for images and embeds to prevent CLS.

Generated from the current SKILL.md.

Does this skill cover all three Core Web Vitals?
Yes. It covers LCP (Largest Contentful Paint), INP (Interaction to Next Paint), and CLS (Cumulative Layout Shift), with optimization strategies and code examples for each.
What tools or libraries does this skill assume I'm using?
It's framework-agnostic but includes examples for React/Vue, Web APIs like scheduler.yield() and requestIdleCallback, and references the web-vitals library for field debugging.
Does this include debugging tools or just optimization patterns?
Both. It provides PerformanceObserver code snippets to identify LCP elements and slow interactions, plus guidance on using the web-vitals library with Long Animation Frame attribution for real-user data.
Will this help improve my Google Search ranking?
Yes. Google measures Core Web Vitals at the 75th percentile for search ranking—the skill explains the thresholds and how to meet them.
Does this cover third-party script optimization?
Yes. It includes patterns for lazy-loading heavy widgets and avoiding third-party blocking, particularly relevant for INP.

Generated from the current SKILL.md. These answers refresh after source changes.