Claude Cursor GitHub Copilot Skill

critical-rendering-path-review

Review page-load resource sequencing, render-blocking CSS/JS, layout-shift sources, and Core Web Vitals (LCP/CLS/INP) budget adherence against the critical rendering path model, explicitly separating lab/synthetic measurement (Lighthouse) from field/real-user measurement (CrUX/RU

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download vincentchuwaichow-vanguard-frontier-agentic-skills_frontend_critical-rendering-path-review-febe32a.zip · 13 KB
Part of vincentchuwaichow/vanguard-frontier-agentic — 293 skills

Install

skills CLI npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/critical-rendering-path-review
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
Git git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Critical Rendering Path Review

Purpose

Performance regressions in the critical rendering path (render-blocking resources, layout-shift-inducing patterns, oversized LCP candidates) are cheap to introduce and expensive to diagnose after the fact, and lab data (a single Lighthouse run) frequently disagrees with field data (real users on real networks/devices) in ways that matter — a change that looks fine in a fast CI-runner Lighthouse run can regress Core Web Vitals for the actual user population. This skill reviews resource-loading order and layout-shift risk against the browser's actual parse/style/layout/paint pipeline, and enforces the lab-vs-field evidence distinction so performance verdicts aren't overclaimed.

When to use

Use this skill when the user asks to:

  • review a diff for render-blocking CSS/JS, resource-loading order, or <link> resource-hint (preload/prefetch/preconnect) usage,
  • diagnose or prevent Cumulative Layout Shift (CLS) sources (unsized images/embeds, late-injected content above existing content, web-font swap),
  • assess Largest Contentful Paint (LCP) or Interaction to Next Paint (INP) budget adherence for a page or component,
  • reconcile conflicting lab (Lighthouse) vs. field (CrUX/RUM) performance data,
  • set or enforce a performance budget for a page/route.

Context7 Documentation Protocol

Render-blocking semantics, <link> resource-hint behavior, and Core Web Vitals thresholds/definitions change as browser implementations and measurement methodology evolve (e.g. INP replaced FID as a Core Web Vital in May 2024) — never assert them from memory.

  1. Call ToolSearch with query "context7" (or "select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs") to load the Context7 tools if they are not already loaded in this session.
  2. Call mcp__Context7__resolve-library-id for the relevant documentation set — for this skill that is almost always MDN (/mdn/content, or /websites/developer_mozilla_en-us if the former lacks coverage for the query).
  3. Call mcp__Context7__query-docs for the specific mechanism in question — e.g. "render-blocking <link> and <script> behavior", "rel=preload as and crossorigin requirements", "LargestContentfulPaint / layout-shift performance entry semantics" — before ruling on it. Do this per review, not once from memory of a prior session.
  4. web.dev is the primary source for Core Web Vitals thresholds (good/needs-improvement/poor cutoffs) and is not currently indexed in Context7; treat threshold numbers pulled from official_docs/WebFetch as documentation-based rather than Context7-verified, and say so explicitly. Use Context7/MDN to verify the underlying mechanism (what LCP/CLS/INP actually measure, what a PerformanceObserver reports) wherever possible.
  5. Prefer the official spec/MDN wording over this skill's own paraphrase when the two could be read to disagree; cite the resolved doc URL in the finding.
  6. If Context7 is unavailable or returns no relevant match, fall back to the URLs in official_docs / references/*.md, and explicitly mark the claim documentation-based (Context7 unavailable) rather than presenting it as freshly verified.
  7. Never invent a <link> attribute, performance-entry field, or Core Web Vitals threshold that no queried source confirms.

Lean operating rules

  • Always separate lab data (synthetic, single-run, deterministic-ish, from Lighthouse/CI) from field data (real-user, aggregated, from CrUX or RUM tooling) explicitly in every finding — never present a Lighthouse score as if it were a field-validated user-experience claim.
  • Trace resource-loading order against the actual critical rendering path (HTML parse → DOM/CSSOM construction → render tree → layout → paint → composite) rather than asserting 'this is render-blocking' without identifying which pipeline stage it blocks.
  • Every image, video, or embed must have explicit width/height or aspect-ratio reserved space to prevent CLS; flag any that don't.
  • Flag web-font loading without a font-display strategy or preload for the LCP-critical font, since font-swap/flash is a common unaddressed CLS and LCP-delay source.
  • Query current web.dev/MDN Core Web Vitals thresholds before asserting a pass/fail budget verdict — LCP/CLS/INP thresholds and measurement methodology have changed (INP replaced FID as a Core Web Vital in May 2024); never assert current thresholds from memory.
  • Do not recommend preload/prefetch/preconnect for third-party origins without weighing the connection-establishment cost against the information-leakage/timing tradeoff.
  • Treat a single synthetic Lighthouse run as insufficient evidence for a production performance claim; flag the need for field data (CrUX/RUM) before asserting a real-user-experience verdict.
  • Never suggest dropping Subresource Integrity (SRI) or bypassing CSP script-src allow-listing as a performance optimization.

References

Load these only when needed:

Response minimum

Return, at minimum:

  • the critical-rendering-path stage(s) affected by the change in scope (parse/style/layout/paint/composite),
  • the render-blocking resource audit for any new/modified <link>, <script>, or @import,
  • the CLS-source audit (unsized media, font-swap, late-injected content) for the page/component in scope,
  • the LCP/CLS/INP budget verdict, explicitly labeled as lab evidence, field evidence, or inference,
  • residual risk notes for anything requiring live Lighthouse/CrUX/RUM data beyond this static review.
Files (vanguard-frontier-agentic)
  • references
    • lab-vs-field-evidence.md 6.8 KB
      # Lab vs. Field Evidence Reconciliation
      
      > Core Web Vitals thresholds (the good/needs-improvement/poor cutoffs for LCP/CLS/INP) live in web.dev, which is not currently indexed in Context7. Treat specific threshold numbers as `documentation-based` and re-verify against `https://web.dev/vitals` and the metric-specific web.dev articles before asserting a pass/fail budget verdict — do not assert them from memory or from this file, which does not restate them for that reason.
      
      ## What people get wrong
      
      The naive story is:
      
      > "I ran Lighthouse, the score is green, performance is fine."
      
      Wrong, and it is wrong in a specific, well-documented way: Lighthouse is a **lab** tool — a single synthetic run, on a simulated or fixed device/network profile, usually with a cold cache, on whatever machine ran it (a fast CI runner or an engineer's laptop are both faster and more consistent than most real user devices/networks). It cannot see what real users on real hardware and real networks actually experience. A change can score green in a CI Lighthouse run and simultaneously regress Core Web Vitals in the Chrome UX Report (CrUX) for the real user population, and the reverse is equally possible — a lab regression that never shows up in field data because it falls below the threshold real users' devices are sensitive to.
      
      ## Officially grounded distinction
      
      - **Lab data** (Lighthouse, WebPageTest, a local Chrome DevTools trace): synthetic, reproducible, deterministic-ish (modulo system noise), useful for **diagnosing** *why* something is slow because it gives you a full trace/waterfall — but it reflects one simulated environment, not your actual user population's device mix, network conditions, cache state, or extensions/interference.
      - **Field data** (Chrome UX Report / CrUX, or a first-party Real User Monitoring / RUM setup using the `web-vitals` JS library or the underlying Performance APIs directly): aggregated measurements from real page loads by real users, on their actual devices and networks — this is what Core Web Vitals thresholds are actually evaluated against for things like Google Search's page-experience signal, and it is the only data source that can tell you what users actually experienced.
      
      Neither one is a substitute for the other:
      
      - Lab data without field data → you don't know if your synthetic environment represents your real users at all (e.g. testing on fast fiber when 40% of your traffic is mobile on 4G).
      - Field data without lab data → you know something regressed, but you have no trace/waterfall to diagnose *why*, and CrUX is aggregated over a rolling 28-day window, so it lags a deploy by design and can't attribute a regression to a specific commit.
      
      ## Non-negotiable review rules
      
      ### 1. Never present a Lighthouse score as a user-experience claim
      
      A sentence like "LCP is 1.8s, this is fast for users" is not supportable from a Lighthouse run alone — the correct claim is "LCP is 1.8s in this lab run under [specified throttling profile]; field verification via CrUX/RUM is needed to confirm real-user experience." Say which one you have.
      
      ### 2. Label every performance number by its evidence source
      
      Use one of: `lab (Lighthouse/CI)`, `lab (local DevTools trace)`, `field (CrUX)`, `field (RUM)`, `inference (not measured, reasoned from code review)`. Do not present an inferred estimate ("this should improve LCP by roughly X") as if it were measured.
      
      ### 3. CrUX has structural limitations — know them before citing it
      
      CrUX data: is a rolling aggregate (commonly a 28-day window) so it cannot attribute a regression to a specific deploy without waiting; only reports origins/URLs with sufficient real-world traffic (low-traffic pages may have no CrUX data at all); reports field percentiles (commonly the 75th percentile) rather than a single number, so "the field LCP" is actually a distribution, not a point value — always specify which percentile a cited number represents. Flag a claim that treats CrUX as instantly reflecting today's deploy, or as covering a low-traffic page it may not have data for.
      
      ### 4. A single Lighthouse run is not enough even as lab evidence
      
      Lab measurement variance (system load, thermal throttling, background processes) means a single run of Lighthouse is not reliable evidence on its own — multiple runs (or a controlled tool that already runs multiple iterations and reports median/percentile) are needed before treating a lab number as stable evidence, not just a single sample.
      
      ### 5. Reconciling disagreement between lab and field
      
      When lab says "fine" and field says "regressed" (or vice versa), the disagreement itself is the finding — investigate rather than picking whichever number supports the desired conclusion. Common causes: the lab throttling profile doesn't represent the real device/network mix (e.g. desktop-only lab testing for a mostly-mobile audience); the lab run has a warm cache the CI step didn't clear, but real first-time visitors don't; the regression is specific to a code path/interaction that the lab script's test URL/flow doesn't exercise (e.g. INP on a specific interactive element the Lighthouse run never clicks, since Lighthouse's synthetic run cannot fully simulate INP the way field RUM data — which requires observed real interactions — can).
      
      ## Minimal safe review flow
      
      1. Identify what evidence is actually available for the claim being reviewed (lab-only, field-only, both, or neither/inference).
      2. If only lab data exists for a production-impacting claim, state that field verification is outstanding as a residual risk rather than asserting a final verdict.
      3. If lab and field data disagree, investigate the throttling-profile/cache-state/traffic-mix explanations above before concluding either number is "wrong."
      4. Cite the specific percentile (e.g. p75) and time window for any field number, and the specific throttling/device profile for any lab number.
      5. Re-verify current LCP/CLS/INP threshold cutoffs against `https://web.dev/vitals` before stating a pass/fail budget verdict — do not reuse a remembered threshold from a prior review.
      
      ## When to push back
      
      Push back if the user says:
      
      - "the Lighthouse score is green, ship it" — for anything with real production traffic, ask whether field data (CrUX or RUM) exists or is planned to confirm it,
      - "CrUX shows we're fine" for a page/route that just shipped a change days ago — CrUX's rolling window means it may not yet reflect that change,
      - "just average the field numbers" — Core Web Vitals are evaluated at specific percentiles (commonly p75), not the mean; averaging hides the tail experience that the metric is specifically designed to surface,
      - "we don't need RUM, Lighthouse in CI is enough" for a production application with a real, diverse user base — lab-only measurement cannot see device/network heterogeneity that field data is specifically designed to capture.
      
    • layout-shift-sources.md 6.7 KB
      # Layout-Shift Source Catalog
      
      > Verify `LayoutShift`/`LayoutShiftAttribution` performance-entry semantics against current MDN docs via Context7 before citing exact scoring behavior — the CLS scoring window/session-gap algorithm has changed since CLS's introduction. Treat any specific numeric session-window value as `documentation-based` and re-verify rather than asserted from memory.
      
      ## What people get wrong
      
      The common bad assumption is:
      
      > "CLS is about images without `width`/`height` — I checked, they're all fine."
      
      Incomplete. Unsized media is the textbook example, but it is one of at least five distinct source categories, and a page can pass a naive "all images have dimensions" check while still shipping a significant CLS regression.
      
      ## Officially grounded definition
      
      Per MDN's CLS glossary entry and the Layout Instability API (`LayoutShift`/`LayoutShiftAttribution`), a layout shift is scored when a visible element's start position changes between two rendered frames, without that change being the direct result of a user interaction. `LayoutShiftAttribution` reports the specific DOM node(s) responsible along with `previousRect`/`currentRect`, which is the ground-truth way to attribute a shift to a specific element rather than guessing from a diff.
      
      ## Source categories to audit
      
      ### 1. Unsized media (the well-known one)
      
      Any `<img>`, `<video>`, `<iframe>`, or `<embed>` without explicit `width`/`height` attributes (or a CSS `aspect-ratio`/explicit sized container) reserves no space before the resource loads, so its arrival pushes surrounding content. This applies equally to background images used as layout-affecting content and to responsive images (`srcset`) — the reserved box must match the *intrinsic* aspect ratio, not just have some placeholder height that doesn't match the eventual rendered size.
      
      ### 2. Web-font swap (FOIT/FOUT)
      
      A font that loads after initial text paint and has different metrics (x-height, glyph width) than the fallback font shifts every line it affects when it swaps in. This is invisible to an "images have dimensions" check entirely. Mitigations to look for:
      
      - `font-display: swap` (or `optional`) on `@font-face`, chosen deliberately rather than defaulted to `auto`/`block`.
      - A `<link rel="preload" as="font" crossorigin>` for the LCP-critical font so it's fetched earlier and the swap window is shorter.
      - Font-metric-matching fallback stacks (e.g. via `size-adjust`/`ascent-override`/`descent-override` in a matching `@font-face` fallback declaration, or a generated fallback via a tool that computes these) to minimize the visual delta when the swap happens, when the swap itself can't be eliminated.
      
      Flag any new `@font-face` with neither a `font-display` strategy nor a metric-matched fallback as an unaddressed CLS/LCP risk.
      
      ### 3. Content injected above existing content
      
      Any DOM insertion above the current viewport's visible content — a banner, cookie-consent bar, ad slot, or async-loaded promo — that doesn't have space reserved for it shifts everything below. This is a frequent CLS source that has nothing to do with media sizing at all. Audit: does the container reserve a fixed or `min-height` slot before the async content resolves, or does content just get prepended/inserted into flow?
      
      ### 4. Animations that trigger layout instead of compositing
      
      CSS animations/transitions on `top`/`left`/`width`/`height`/`margin` (layout-triggering properties) rather than `transform`/`opacity` (compositor-only properties) can register as layout shifts if they affect other elements' positions, and are also a distinct main-thread-cost problem independent of CLS. Flag any newly added animation on a layout-affecting property and ask whether a `transform`-based equivalent achieves the same visual effect.
      
      ### 5. FOUC/late-applied CSS affecting already-painted content
      
      If content paints before a stylesheet (or a `<style>` block inserted by JS) fully applies, and the styles change box dimensions, that is a layout-shift source distinct from font swap — e.g. a CSS-in-JS solution that injects styles after first paint, or a critical-CSS strategy that inlines an incomplete subset and loads the rest async without accounting for elements that need the deferred rules for correct sizing.
      
      ## Non-negotiable review rules
      
      - Do not accept "images have width/height" as a complete CLS review — walk all five categories above.
      - Any element inserted above existing viewport content without a reserved slot is a blocking finding, not a nice-to-have fix, if it's likely to occur after first paint (ads, consent banners, personalization banners, notification bars).
      - New `@font-face` rules must specify a deliberate `font-display` value; flag `auto`/default (browser-dependent, commonly behaves like `block`) as unreviewed.
      - New layout-triggering animations (`top`/`left`/`width`/`height`/`margin` in `@keyframes` or `transition`) should be flagged with a suggested `transform`/`opacity` alternative when the visual intent allows it.
      - Distinguish shifts caused by user interaction (which are explicitly excluded from CLS scoring, e.g. an accordion the user clicked to expand) from unexpected shifts — don't flag legitimate, user-triggered layout changes as CLS problems.
      
      ## Minimal safe review flow
      
      1. Identify every element that renders asynchronously or after a network/font/JS dependency resolves (images, fonts, injected banners, lazy content, animated elements).
      2. For each, check whether visual space is reserved before it resolves (`width`/`height`, `aspect-ratio`, `min-height` container, skeleton placeholder).
      3. For fonts specifically, confirm a `font-display` strategy and, for LCP-critical fonts, a preload.
      4. For animations, confirm they animate compositor-only properties where visually equivalent.
      5. State whether the verdict is markup/CSS-inferred (`inference`) or confirmed via a live `LayoutShift`/`LayoutShiftAttribution` observer trace (`live evidence`) — attribution data is the only way to confirm which specific element actually caused a measured shift versus which one merely looks suspicious in markup.
      
      ## When to push back
      
      Push back if the user says:
      
      - "it's just one image, CLS won't notice" — a single large above-the-fold image is often the single biggest CLS contributor on a page,
      - "we'll add the font-display later" — that is deferring a known, cheap-to-fix CLS/LCP source indefinitely,
      - "the banner only shows sometimes, so it doesn't count" — intermittent injection is still a real-user-experience regression for the users who see it, and CrUX aggregates across all real loads including that one,
      - "let's just wrap it in `overflow: hidden` so the shift isn't visible" — that hides the symptom from a visual check without preventing the actual layout recalculation, and does not necessarily improve the measured CLS score.
      
    • resource-loading-order.md 7.4 KB
      # Resource-Loading Order and Render-Blocking Audit
      
      > Verify exact `<link>`/`<script>` attribute behavior against current MDN docs via Context7 before ruling — browser render-blocking rules and resource-hint attributes are implementation-defined and have changed (e.g. `blocking="render"`, `fetchpriority`). Do not assert them from memory.
      
      ## What people get wrong
      
      The naive story is:
      
      > "Put scripts at the bottom of `<body>` and it's fixed."
      
      Incomplete. That mitigates one failure mode (parser-blocking synchronous `<script>` in `<head>`) but says nothing about CSS blocking, resource priority, third-party origin cost, or whether the thing you deferred was actually needed for first paint.
      
      ## Officially grounded pipeline
      
      Per MDN's critical rendering path reference: the browser builds the DOM as HTML is parsed, builds the CSSOM from requested/inline styles, combines DOM + CSSOM into the render tree, computes layout, then paints and composites pixels. Two consequences follow directly from that pipeline:
      
      - **CSS is render-blocking by default.** The browser withholds first paint until it has the CSSOM, specifically to avoid a flash of unstyled content. A `<link rel="stylesheet">` in `<head>` blocks rendering unless explicitly marked otherwise (e.g. via a non-render-blocking media query that doesn't match the current viewport, or `blocking` control on supporting elements).
      - **A synchronous `<script>` (no `async`/`defer`/`type="module"`) blocks HTML parsing at the point it appears,** because the parser must assume the script could call `document.write` or otherwise mutate the DOM before parsing continues. It does not block CSSOM construction, but it can be blocked *by* an earlier stylesheet (browsers commonly delay script execution until preceding CSS has loaded, since the script might query computed style).
      
      So "render-blocking" is not one failure mode — audit each resource against which stage it blocks:
      
      | Resource | Blocks HTML parse? | Blocks first paint? |
      |---|---|---|
      | `<link rel="stylesheet">` (no disabling media) | No | Yes |
      | `<script src="...">` (no async/defer/module) | Yes, at that point | Indirectly (delays DOM/paint readiness) |
      | `<script defer>` | No | No (executes after parse, before `DOMContentLoaded`) |
      | `<script async>` | No | No, but executes whenever it finishes downloading — order not guaranteed relative to other scripts |
      | `<script type="module">` | No (deferred by default) | No |
      | `@import` inside CSS | N/A | Yes, and serializes — it blocks until fetched, adding a network round trip the browser couldn't discover from the HTML in parallel |
      
      Live evidence for a given page: `PerformanceObserver({type: "resource", buffered: true})` and check `entry.renderBlockingStatus === "blocking"` (per `PerformanceResourceTiming.renderBlockingStatus`), or `performance.getEntriesByType("resource")` filtered the same way. This is the only way to get a ground-truth render-blocking verdict for a *live* page rather than an inferred one from reading markup.
      
      ## Non-negotiable review rules
      
      ### 1. Classify every new/modified `<link>` and `<script>` by blocking behavior, not by intent
      
      Do not accept "it's deferred" as true because the author says so — check the actual attribute (`defer`, `async`, `type="module"`, `blocking`) and its placement.
      
      ### 2. `@import` in CSS is a hidden render-blocking network round trip
      
      Flag any new `@import` in a stylesheet that's itself render-blocking. The browser cannot discover and start fetching an `@import`-ed stylesheet until it has already parsed the CSS that contains it — it cannot be discovered by the HTML preload scanner the way a `<link>` can. Prefer a second `<link rel="stylesheet">` in the HTML.
      
      ### 3. Resource hints are not interchangeable
      
      Per MDN's `<link>` reference and the `dns-prefetch`/`preconnect`/`preload` guides:
      
      - `dns-prefetch` — resolve DNS only. Cheapest hint; useful for many possible-but-uncertain origins.
      - `preconnect` — DNS + TCP + TLS handshake. More expensive per origin; browsers cap how many they'll act on, so do not `preconnect` to more than a handful of origins.
      - `preload` — fetch a *specific, known-needed* resource at high priority, before the parser would otherwise discover it. Requires the correct `as` value (`script`, `style`, `font`, `image`, etc.) or the browser may apply the wrong priority/type-check and silently double-fetch. Cross-origin font preloads require `crossorigin` even for same-site font hosting, because fonts are fetched in "anonymous" CORS mode regardless of same-origin-ness.
      - `modulepreload` — the module-script-specific equivalent of `preload`, which also allows the browser to parse and cache the module graph ahead of execution.
      - `prefetch` — low-priority fetch for a resource likely needed for a *future* navigation, not the current render. Do not use it for anything on the current page's critical path — it competes for bandwidth at low priority and is the wrong tool if the goal is to affect *this* page's LCP.
      
      A `preload` misused for a resource that turns out unused within a few seconds of load produces a Chrome DevTools/Lighthouse warning and wastes bandwidth — flag speculative preloads with no confirmed use.
      
      ### 4. Third-party resource hints have a cost, not just a benefit
      
      `preconnect`/`dns-prefetch` to a third-party origin (analytics, font CDN, ad tech, social widget) opens a connection or resolves DNS to that origin earlier than the page would otherwise need to — which also means that origin observes the visit earlier and independent of whether the resource is ever actually used. Weigh this against the latency win; do not recommend blanket `preconnect` to every third-party origin referenced anywhere on the page.
      
      ### 5. LCP-candidate resource should be the highest-priority fetch on the page
      
      If the LCP element is a background `<img>`, hero image, or web font, confirm it is discoverable by the HTML preload scanner (i.e. present as a real `<img src>`/`<link>` in markup, not injected by a blocking JS bundle) and, where warranted, has an explicit `fetchpriority="high"` or `<link rel="preload">`. An LCP image that only becomes discoverable after a render-blocking JS bundle executes is a common, easily fixed regression.
      
      ## Minimal safe review flow
      
      1. List every `<link>`, `<script>`, and `@import` added or modified in the diff.
      2. Classify each by blocking behavior per the table above (parse-blocking / paint-blocking / neither).
      3. For each resource hint (`preload`/`prefetch`/`preconnect`/`dns-prefetch`/`modulepreload`), confirm it targets a resource actually needed for *this* page's first render, has correct `as`/`type`/`crossorigin`, and isn't redundant with browser-default discovery.
      4. Identify the LCP candidate and confirm it is discoverable without executing render-blocking JS first.
      5. Flag any `@import`, unbounded `preconnect` list, or speculative preload as findings, not silent passes.
      6. State whether the verdict is markup-inferred (`inference`) or confirmed via a live `PerformanceObserver`/DevTools trace (`live evidence`).
      
      ## When to push back
      
      Push back if the user asks for:
      
      - `preconnect` to every third-party domain referenced anywhere in the codebase "just in case,"
      - moving all `<script>` tags to `async` without checking execution-order dependencies between them,
      - a blanket `preload` for every image on the page instead of just the LCP candidate,
      - removing a render-blocking stylesheet without confirming what visual state exists before it loads (flash of unstyled content is a real regression, not just a metric).
      
  • metadata.json 1.7 KB
    {
      "id": "critical-rendering-path-review",
      "name": "Critical Rendering Path Review",
      "type": "skill",
      "provider": "frontend",
      "harnesses": [
        "codex",
        "claude-code",
        "cursor",
        "gemini",
        "kiro",
        "other"
      ],
      "summary": "Reviews page load sequencing — resource loading order, render-blocking CSS/JS, layout-shift risk, and Core Web Vitals budget adherence — separating lab (Lighthouse/synthetic) data from field (CrUX/RUM) data so performance claims are evidence-graded rather than asserted.",
      "source_type": "original",
      "official_docs": [
        "https://web.dev/articles/critical-rendering-path",
        "https://web.dev/articles/optimize-lcp",
        "https://web.dev/articles/cls",
        "https://web.dev/articles/inp",
        "https://web.dev/vitals",
        "https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path",
        "https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link",
        "https://developer.chrome.com/docs/lighthouse/overview"
      ],
      "security_notes": "Flag preload/prefetch/preconnect resource hints pointed at third-party origins without considering the information-leakage/timing implications of establishing early connections to those origins. Flag any performance 'optimization' that removes Subresource Integrity (SRI) from a script/style tag to save a round trip — integrity checks are not a discretionary performance cost. Do not recommend inlining third-party scripts to avoid a network request in a way that bypasses CSP script-src allow-listing.",
      "last_verified": "2026-07-02",
      "path": "skills/frontend/critical-rendering-path-review",
      "author": "github: VincentChuWaiChow",
      "version": "0.1.0"
    }
    
  • SKILL.md 6.7 KB
    ---
    name: critical-rendering-path-review
    description: Review page-load resource sequencing, render-blocking CSS/JS, layout-shift sources, and Core Web Vitals (LCP/CLS/INP) budget adherence against the critical rendering path model, explicitly separating lab/synthetic measurement (Lighthouse) from field/real-user measurement (CrUX/RUM) so performance claims are evidence-graded rather than asserted from a single synthetic run.
    allowed-tools: Read Grep Glob Bash(git diff:*) WebFetch
    metadata:
      author: "github: VincentChuWaiChow"
      version: "0.1.0"
      updated: "2026-07-02"
      category: operational
    ---
    
    # Critical Rendering Path Review
    
    ## Purpose
    
    Performance regressions in the critical rendering path (render-blocking resources, layout-shift-inducing patterns, oversized LCP candidates) are cheap to introduce and expensive to diagnose after the fact, and lab data (a single Lighthouse run) frequently disagrees with field data (real users on real networks/devices) in ways that matter — a change that looks fine in a fast CI-runner Lighthouse run can regress Core Web Vitals for the actual user population. This skill reviews resource-loading order and layout-shift risk against the browser's actual parse/style/layout/paint pipeline, and enforces the lab-vs-field evidence distinction so performance verdicts aren't overclaimed.
    
    ## When to use
    
    Use this skill when the user asks to:
    
    - review a diff for render-blocking CSS/JS, resource-loading order, or `<link>` resource-hint (preload/prefetch/preconnect) usage,
    - diagnose or prevent Cumulative Layout Shift (CLS) sources (unsized images/embeds, late-injected content above existing content, web-font swap),
    - assess Largest Contentful Paint (LCP) or Interaction to Next Paint (INP) budget adherence for a page or component,
    - reconcile conflicting lab (Lighthouse) vs. field (CrUX/RUM) performance data,
    - set or enforce a performance budget for a page/route.
    
    ## Context7 Documentation Protocol
    
    Render-blocking semantics, `<link>` resource-hint behavior, and Core Web Vitals thresholds/definitions change as browser implementations and measurement methodology evolve (e.g. INP replaced FID as a Core Web Vital in May 2024) — never assert them from memory.
    
    1. Call `ToolSearch` with query `"context7"` (or `"select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs"`) to load the Context7 tools if they are not already loaded in this session.
    2. Call `mcp__Context7__resolve-library-id` for the relevant documentation set — for this skill that is almost always MDN (`/mdn/content`, or `/websites/developer_mozilla_en-us` if the former lacks coverage for the query).
    3. Call `mcp__Context7__query-docs` for the specific mechanism in question — e.g. "render-blocking `<link>` and `<script>` behavior", "`rel=preload` `as` and `crossorigin` requirements", "LargestContentfulPaint / layout-shift performance entry semantics" — before ruling on it. Do this per review, not once from memory of a prior session.
    4. web.dev is the primary source for Core Web Vitals *thresholds* (good/needs-improvement/poor cutoffs) and is not currently indexed in Context7; treat threshold numbers pulled from `official_docs`/`WebFetch` as `documentation-based` rather than `Context7-verified`, and say so explicitly. Use Context7/MDN to verify the underlying *mechanism* (what LCP/CLS/INP actually measure, what a `PerformanceObserver` reports) wherever possible.
    5. Prefer the official spec/MDN wording over this skill's own paraphrase when the two could be read to disagree; cite the resolved doc URL in the finding.
    6. If Context7 is unavailable or returns no relevant match, fall back to the URLs in `official_docs` / `references/*.md`, and explicitly mark the claim `documentation-based (Context7 unavailable)` rather than presenting it as freshly verified.
    7. Never invent a `<link>` attribute, performance-entry field, or Core Web Vitals threshold that no queried source confirms.
    
    ## Lean operating rules
    
    - Always separate lab data (synthetic, single-run, deterministic-ish, from Lighthouse/CI) from field data (real-user, aggregated, from CrUX or RUM tooling) explicitly in every finding — never present a Lighthouse score as if it were a field-validated user-experience claim.
    - Trace resource-loading order against the actual critical rendering path (HTML parse → DOM/CSSOM construction → render tree → layout → paint → composite) rather than asserting 'this is render-blocking' without identifying which pipeline stage it blocks.
    - Every image, video, or embed must have explicit width/height or `aspect-ratio` reserved space to prevent CLS; flag any that don't.
    - Flag web-font loading without a `font-display` strategy or preload for the LCP-critical font, since font-swap/flash is a common unaddressed CLS and LCP-delay source.
    - Query current web.dev/MDN Core Web Vitals thresholds before asserting a pass/fail budget verdict — LCP/CLS/INP thresholds and measurement methodology have changed (INP replaced FID as a Core Web Vital in May 2024); never assert current thresholds from memory.
    - Do not recommend `preload`/`prefetch`/`preconnect` for third-party origins without weighing the connection-establishment cost against the information-leakage/timing tradeoff.
    - Treat a single synthetic Lighthouse run as insufficient evidence for a production performance claim; flag the need for field data (CrUX/RUM) before asserting a real-user-experience verdict.
    - Never suggest dropping Subresource Integrity (SRI) or bypassing CSP `script-src` allow-listing as a performance optimization.
    
    ## References
    
    Load these only when needed:
    
    - [Resource-loading order and render-blocking audit](references/resource-loading-order.md) — use when tracing which resources block first paint/LCP and how to reorder or hint them (preload/defer/async/module).
    - [Layout-shift source catalog](references/layout-shift-sources.md) — use when auditing a page/component for CLS sources beyond unsized media (late web-font swap, injected banners/ads, animation-triggered reflow).
    - [Lab vs. field evidence reconciliation](references/lab-vs-field-evidence.md) — use when Lighthouse (lab) and CrUX/RUM (field) data disagree, or when a performance claim needs to be evidence-graded for a stakeholder deliverable.
    
    ## Response minimum
    
    Return, at minimum:
    
    - the critical-rendering-path stage(s) affected by the change in scope (parse/style/layout/paint/composite),
    - the render-blocking resource audit for any new/modified `<link>`, `<script>`, or `@import`,
    - the CLS-source audit (unsized media, font-swap, late-injected content) for the page/component in scope,
    - the LCP/CLS/INP budget verdict, explicitly labeled as lab evidence, field evidence, or inference,
    - residual risk notes for anything requiring live Lighthouse/CrUX/RUM data beyond this static review.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related