Add comprehensive metrics and engines documentation

Complete the documentation suite with:
- Deep-dive metrics reference (LCP, FCP, CLS, TBT, TTFB)
- Detailed testing engines comparison (Sitespeed vs PSI)
- Why TBT is the killer metric for rds.ink
- How to fix each metric using Hummingbird
- Score differences and when to use each engine

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 05:58:12 +10:00
parent 335d9a76e1
commit 76523db177
2 changed files with 659 additions and 0 deletions

View File

@@ -0,0 +1,326 @@
# Performance Metrics Reference
Deep-dive reference for each Core Web Vital metric captured by the seo-intel system.
## The Five Metrics
| Metric | Full Name | Unit | Good | Poor | What Matters |
|--------|-----------|------|------|------|--------------|
| **LCP** | Largest Contentful Paint | milliseconds | ≤2,500ms | ≥4,000ms | When main content appears |
| **FCP** | First Contentful Paint | milliseconds | ≤1,800ms | ≥3,000ms | When ANY content appears |
| **CLS** | Cumulative Layout Shift | unitless (0-1) | ≤0.1 | ≥0.25 | How much page jumps |
| **TBT** | Total Blocking Time | milliseconds | ≤200ms | ≥600ms | JS blocking interactions |
| **TTFB** | Time to First Byte | milliseconds | ≤800ms | ≥1,800ms | Server response speed |
---
## 1. LCP — Largest Contentful Paint
### Definition
The time when the **largest visible element** (image, heading, paragraph block, video) appears on screen.
### Why It Matters
Users need to see that the page is loading. LCP is the best metric for "when does the user perceive the page is starting to load?"
### Thresholds
- **≤ 2.5 seconds:** Good — user feels the page is responding
- **2.5 4.0 seconds:** Needs improvement
- **≥ 4.0 seconds:** Poor — user thinks the page is slow/broken
### What Affects LCP
1. **Server response time (TTFB)** — If the server is slow, everything downstream is slow
2. **Large images/videos above the fold** — Unoptimized media delays LCP
3. **Render-blocking JavaScript**`<script>` in `<head>` delays rendering
4. **Render-blocking CSS** — Large CSS files in `<head>` delay rendering
5. **Font loading** — Web fonts block text rendering (can use `font-display: swap`)
### How to Fix
1. **Optimise TTFB** (server response)
- Cache dynamic pages
- Optimise database queries
- Use a CDN for static content
2. **Lazy-load below-the-fold images**
- Use `loading="lazy"` on `<img>` tags
- Hummingbird has automatic image lazy-loading
3. **Defer non-critical JavaScript**
- Add `defer` attribute to scripts that aren't needed for initial render
- Move analytics/tracking to the bottom
4. **Critical CSS inlining** (advanced)
- Inline the CSS needed for above-the-fold content
- Defer the rest with `<link rel="preload">`
---
## 2. FCP — First Contentful Paint
### Definition
The time when the browser paints the **first piece of non-whitespace content** to the screen. This could be:
- Text
- An image
- An SVG
- A coloured background
- Anything that's not white
### Why It Matters
FCP is the user's first visual cue that the page is loading. It happens before LCP.
### Timeline Relationship
```
0ms: User clicks link
|
50ms: Server starts responding
|
144ms (TTFB): Browser receives first bytes
|
2,116ms (FCP): Browser paints first content (this page)
|
2,500ms (LCP): Browser paints largest content
|
4,000ms: Page is fully interactive
```
### Thresholds
- **≤ 1.8 seconds:** Good
- **1.8 3.0 seconds:** Needs improvement (this page is at 2.1s)
- **≥ 3.0 seconds:** Poor
### What Affects FCP
1. **TTFB** — Server has to respond first
2. **HTML parsing** — Browser must parse HTML to find content
3. **Render-blocking resources** — CSS/JS in `<head>` delay rendering
4. **Font loading** — If fonts are slow, text doesn't paint until fonts arrive
### How to Fix
Same as LCP:
1. Optimise TTFB
2. Defer render-blocking resources
3. Lazy-load heavy assets
---
## 3. CLS — Cumulative Layout Shift
### Definition
**Measure of unwanted layout changes** after the page is visually complete.
Example: You're reading an article, about to click a button, and an ad loads above the button, pushing the button down. You accidentally click the ad instead. That's layout shift.
### Why It Matters
CLS directly impacts **user experience frustration**. Unexpected layout changes are one of the most annoying things on the web.
### Measurement
```
CLS = sum of all individual layout shifts
Each shift is: (fraction of viewport moved) × (distance moved)
Example:
- Ad loads, pushes button down by 50px
- Viewport is 800px tall
- Shift score = (0.5 × 800) / 800 = 0.5
If this happens once, CLS = 0.5
If it happens three times (each 0.5), CLS = 1.5
```
Shifts that happen > 500ms after user input are excluded (they don't surprise the user).
### Thresholds
- **≤ 0.1:** Good — page is stable
- **0.1 0.25:** Needs improvement — some shifts happening
- **≥ 0.25:** Poor — page is jumpy
### rds.ink Status: 0.0 = PERFECT ✓
This page does NOT shift after load. The images load lazily, product cards maintain their size, nothing pops up. Great job.
### What Causes CLS
1. **Unset image/video dimensions** — Browser doesn't know how much space to reserve
2. **Ads/widgets loading after page render** — Third-party content shifts layout
3. **Custom fonts** — Text changes size when font finishes loading
4. **Embeds/iframes** — External content pushes layout
5. **Animations that move elements** — Animation changing `top` / `left` / `margin`
### How to Fix
1. **Set dimensions on images**
```html
<img src="..." width="800" height="600" />
<!-- or in CSS -->
img { aspect-ratio: 800 / 600; }
```
2. **Reserve space for ads/lazy content**
```html
<div style="width: 300px; height: 250px;">
<!-- ad will load here -->
</div>
```
3. **Use `font-display: swap`**
```css
@font-face {
font-family: 'Custom';
src: url(...);
font-display: swap; /* show fallback first, swap when custom loads */
}
```
4. **Animations: use `transform` instead of `top`/`left`**
```css
/* GOOD: transform doesn't trigger layout recalc */
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}
/* BAD: left does trigger layout recalc */
@keyframes slide {
from { left: 0; }
to { left: 100px; }
}
```
---
## 4. TBT — Total Blocking Time 🔴 **MOST COMMON PROBLEM**
### Definition
**How long JavaScript is executing on the main thread, blocking all user interactions.**
The browser can only do one thing at a time on the main thread:
- Parse HTML
- Execute JavaScript
- Render CSS
- Handle user input
If JavaScript is running, the browser **cannot** respond to clicks, scrolls, or keypresses.
### Why It Matters
A page with high TBT **feels frozen**. User clicks a button, nothing happens for 1+ seconds. The page is technically loaded, but unusable.
### Measurement
```
JavaScript task execution timeline:
0ms ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 200ms (long task, blocks for 200ms)
User clicks button during this
but browser doesn't respond
200ms (JavaScript done) → Click now registers (if still there)
```
TBT = sum of all "blocking" time. A task is "blocking" if it takes > 50ms.
For example:
- 5 JavaScript tasks, each 100ms = TBT of 5 × 50ms = 250ms blocking
- 2 JavaScript tasks, each 1,000ms = TBT of 2 × 950ms = 1,900ms blocking
### Thresholds
- **≤ 200ms:** Good — page feels snappy
- **200 600ms:** Needs improvement — noticeable sluggishness
- **≥ 600ms:** Poor — page feels frozen
### rds.ink Status: 1,807ms = CRITICAL 🔴
The page has **1,800ms of JavaScript execution blocking interactions**. During page load, the user cannot interact for 1.8 seconds.
This is why the score is 77 instead of 95.
### What Causes High TBT
1. **Large JavaScript bundles** (1.8 MB on this page)
2. **Synchronous JavaScript execution** — No chunking or deferring
3. **Too many plugins** — Each plugin adds code to parse/execute
4. **Unoptimised heavy libraries** — jQuery, older frameworks
5. **No code-splitting** — Entire app loads upfront instead of as-needed
### How to Fix (for WordPress/Hummingbird)
1. **Defer non-critical JavaScript** (add `defer` attribute)
- Page renders first
- Scripts load in background
- TBT moves to after page is interactive
2. **Lazy-load heavy plugins** (load only when needed)
- Gallery/lightbox: load when user clicks product
- Booking widget: load only on booking page
3. **Disable unused plugins** (every plugin = more JS)
4. **Code-split large bundles** (Webpack/bundler feature)
- Don't load everything upfront
- Load only what's visible
5. **Minify/compress JavaScript** (reduce parse time)
### Expected Impact of Fixes
- Current: 1,807ms blocking
- After defer JS: ~400ms
- After lazy-load: ~150ms
- After disabling unused: ~100ms
- **Target: <200ms**
---
## 5. TTFB — Time to First Byte
### Definition
The time from when the browser makes a request until the server sends the first byte of the response.
```
User hits link at 0ms
0-50ms: Network latency
50-100ms: Server processes request
100-144ms: Server sends response (for this page)
↓ This is TTFB
144ms: Browser receives first byte
```
### Why It Matters
TTFB is a **server-side metric**. It measures how fast your infrastructure is.
Everything downstream depends on TTFB. You can't optimise FCP if TTFB is 2 seconds.
### Thresholds
- **≤ 0.8 seconds:** Good
- **0.8 1.8 seconds:** Needs improvement
- **≥ 1.8 seconds:** Poor
### rds.ink Status: 144ms = EXCELLENT ✓
The server responds in 144ms. This is good. Not the bottleneck.
### What Affects TTFB
1. **Server processing time** — Database queries, rendering, etc.
2. **Network latency** — Distance from client to server
3. **Server hardware** — CPU/RAM/I/O speed
4. **Caching** — Is the page/response cached?
5. **DNS resolution** — Domain lookup time
### How to Fix
1. **Enable page caching** (Hummingbird)
- Cached pages: TTFB 50ms
- Uncached: TTFB 144ms
2. **Optimise database queries** (most common bottleneck)
- Use database indexing
- Avoid N+1 queries
- Query Monitor plugin helps diagnose
3. **Use a CDN for static assets**
- CSS, JS, images served from fast edge servers
4. **Upgrade hosting** (if server is slow)
- More CPU cores
- Faster SSD storage
- Better network connection
---
## Summary Table
| Metric | Causes | Quick Fixes |
|--------|--------|-----------|
| **LCP** | Slow TTFB, lazy images, render-blocking JS | Defer JS, optimize TTFB |
| **FCP** | Slow TTFB, render-blocking resources | Defer JS, lazy load |
| **CLS** | Unset dimensions, ads, fonts, animations | Set dimensions, use `transform` |
| **TBT** (THE PROBLEM) | Large JS, too many plugins, sync code | Defer JS, lazy-load plugins, disable unused |
| **TTFB** | Slow server, no cache, slow DB | Enable cache, optimize queries |
---
See also:
- [Score Calculation](02-score-calculation.md) — How these metrics become a 0-100 score
- [Testing Engines](04-testing-engines.md) — How metrics are captured
- [Case Study: rds.ink 77](../case-studies/rds-77-score.md) — Real example with fixes