Files
awesome-copilot/skills/create-web-form/references/web-performance.md
jhauga 27149859a4 Add skill to create web forms
Add skill to create web forms
2026-02-09 19:22:54 -05:00

28 KiB

Web Performance Reference

A consolidated reference guide covering web performance concepts, optimization techniques, and the Performance API, sourced from the Mozilla Developer Network (MDN).


Table of Contents

  1. Web Performance Overview
  2. Performance Fundamentals
  3. Performance Best Practices
  4. HTML Performance
  5. JavaScript Performance
  6. CSS Performance
  7. Performance API
  8. Performance Data
  9. Server Timing
  10. User Timing

1. Web Performance Overview

Source: https://developer.mozilla.org/en-US/docs/Web/Performance

Definition

Web performance encompasses:

  • Objective measurements (load time, frames per second, time to interactive)
  • Perceived user experience of load and response times
  • Smoothness during user interactions (scrolling, animations, button responsiveness)
Target Threshold
Page load indication 1 second
Idling 50ms
Animations 16.7ms (60 FPS)
User input response 50-200ms

Users abandon sites that respond slowly. The goal is to minimize loading and response times while adding features that conceal latency by maximizing availability and interactivity as soon as possible.

Key Performance Metrics

Metric Full Name Definition
FCP First Contentful Paint First time any content appears
LCP Largest Contentful Paint Largest content element visible
CLS Cumulative Layout Shift Visual stability during interactions
INP Interaction to Next Paint Responsiveness to user input
TTFB Time to First Byte Server response time
TTI Time to Interactive Page becomes fully interactive
Jank -- Non-smooth animation or scrolling

Performance API Categories

  • High-precision timing: Sub-millisecond monitoring via stable monotonic clock
  • Navigation Timing: Metrics for page navigation (DOMContentLoaded, load time)
  • Resource Timing: Detailed network timing for individual resources
  • User Timing: Custom marks and measures
  • Long Animation Frames (LoAF): Identifies janky animations
  • Server Timing: Backend performance metrics
  • Page Visibility API: Track document visibility state
  • Background Tasks API (requestIdleCallback()): Queue non-blocking tasks
  • Intersection Observer API: Asynchronously monitor element visibility
  • Network Information API: Detect connection type for adaptive content
  • Battery Status API: Optimize for power-constrained devices
  • Beacon API: Send performance data to analytics
  • Media Capabilities API: Check device media support

Resource Loading Hints

  • DNS-prefetch: Pre-resolve domain names
  • Preconnect: Establish early connections
  • Prefetch: Load resources before needed
  • Preload: Load critical resources early

Monitoring Approaches

  • Real User Monitoring (RUM): Long-term trend analysis from actual users
  • Synthetic Monitoring: Controlled regression testing during development

2. Performance Fundamentals

Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance

Why Web Performance Matters

  • Promotes accessibility and inclusive design
  • Enhances user experience and retention
  • Directly impacts business goals and conversions

Core Components

  • Web page loading performance
  • Content rendering in browsers
  • User agent capabilities and constraints
  • Performance across different user groups

Perceived Performance

Metrics focused on user perception rather than raw milliseconds:

  • Page load time -- initial content availability
  • Responsiveness -- interaction feedback speed
  • Animation smoothness -- visual fluidity
  • Scrolling smoothness -- scroll interaction quality

Optimization Areas

Area Focus Impact
Multimedia (Images) Media optimization based on device capability, size, pixel density Reduces bytes per image
Multimedia (Video) Video compression, audio track removal from background videos Reduces file size
JavaScript Best practices for interactive experiences Improves responsiveness, battery life
HTML DOM node minimization, optimal attribute ordering Improves load and render time
CSS Feature-specific optimization Prevents negative performance impact

Performance Strategy

  • Performance budgets: Set limits on asset sizes
  • Performance culture: Organizational commitment
  • Regression prevention: Avoid bloat over time
  • Mobile-first approaches: Responsive images and adaptive media delivery

3. Performance Best Practices

Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Best_practices

Core Best Practices

  1. Learn the Critical Rendering Path -- Understand how browsers render pages to optimize performance
  2. Use Resource Hints -- rel=preconnect, rel=dns-prefetch, rel=prefetch, rel=preload
  3. Minimize JavaScript -- Only load JavaScript needed for the current page
  4. Optimize CSS -- Address CSS performance factors, load CSS asynchronously when possible
  5. Use HTTP/2 -- Deploy HTTP/2 on your server or CDN
  6. Use a CDN -- Significantly reduces resource load times
  7. Compress Resources -- Use gzip, Brotli, or Zopfli compression
  8. Optimize Images -- Use CSS animations or SVG when possible
  9. Implement Lazy Loading -- Load content outside viewport lazily; use the loading attribute on <img> elements
  10. Focus on User Perception -- Perceived performance matters as much as actual timing

Asynchronous CSS Loading

<link
  id="my-stylesheet"
  rel="stylesheet"
  href="/path/to/my.css"
  media="print" />
<noscript><link rel="stylesheet" href="/path/to/my.css" /></noscript>
const stylesheet = document.getElementById("my-stylesheet");
stylesheet.addEventListener("load", () => {
  stylesheet.media = "all";
});

Critical CSS Inlining

  • Inline CSS for above-the-fold content using <style> tags
  • Prevents Flash of Unstyled Text (FOUT)
  • Improves perceived performance

JavaScript Loading

  • Use async or defer attributes on script tags
  • JavaScript only blocks rendering for elements after the script tag in the DOM

Web Font Best Practices

  1. Font Format Selection: Use WOFF and WOFF2 (built-in compression); compress EOT and TTF with gzip or Brotli
  2. Font Loading Strategy: Use font-display: swap to prevent rendering blocks; optimize font-weight to match the web font closely
  3. Avoid Icon Fonts: Use compressed SVG instead; inline SVG data in HTML to avoid additional HTTP requests

Tools and Measurement

Practices to Avoid

  • Downloading everything unnecessarily
  • Using uncompressed media files

4. HTML Performance

Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/HTML

  • Image and video file sizes (replaced elements)
  • Embedded content delivery (<iframe> elements)
  • Resource loading order

Responsive Image Handling

Using srcset and sizes for different screen widths:

<img
  srcset="480w.jpg 480w, 800w.jpg 800w"
  sizes="(width <= 600px) 480px, 800px"
  src="800w.jpg"
  alt="Family portrait" />

Using srcset for different device resolutions:

<img
  srcset="320w.jpg, 480w.jpg 1.5x, 640w.jpg 2x"
  src="640w.jpg"
  alt="Family portrait" />

Using the <picture> element:

<picture>
  <source media="(width < 800px)" srcset="narrow-banner-480w.jpg" />
  <source media="(width >= 800px)" srcset="wide-banner-800w.jpg" />
  <img src="large-banner-800w.jpg" alt="Dense forest scene" />
</picture>

Lazy Loading

Images:

<img src="800w.jpg" alt="Family portrait" loading="lazy" />

Video (disable preload):

<video controls preload="none" poster="poster.jpg">
  <source src="video.webm" type="video/webm" />
  <source src="video.mp4" type="video/mp4" />
</video>

Iframes:

<iframe src="https://example.com" loading="lazy" width="600" height="400"></iframe>

Iframe Best Practices

Avoid embedded <iframe> elements unless absolutely necessary. Problems include:

  • Extra HTTP requests required
  • Creates a separate page instance (expensive)
  • Cannot share cached assets
  • Separate CSS and JavaScript handling required

Alternative: Use fetch() and DOM scripting to load content into the same page.

JavaScript Loading in HTML

async attribute -- fetches in parallel with DOM parsing, does not block rendering:

<script async src="index.js"></script>

defer attribute -- executes after document parsing but before DOMContentLoaded event.

Module loading -- split code into modules and load parts as needed.

Resource Preloading

<link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4" />

Other rel attributes for performance:

  • rel="dns-prefetch" -- prefetch DNS lookups
  • rel="preconnect" -- pre-establish connections
  • rel="modulepreload" -- preload JavaScript modules
  • rel="prefetch" -- load resources for future navigation

Resource Loading Order

  1. HTML is parsed first in source order
  2. CSS is parsed; linked assets (images, fonts) start fetching
  3. JavaScript is parsed and executed (blocks subsequent HTML parsing by default)
  4. Styling is computed for HTML elements
  5. Rendering of styled content to the screen

Key Takeaway

HTML is simple and fast by default. Focus on:

  • Minimizing bytes downloaded (images and videos)
  • Controlling asset loading order (async, defer, preload)
  • Reducing unnecessary embedded content (iframes)
  • Responsive serving of replaced elements (srcset, picture, media queries)

HTML file size minification provides negligible benefits compared to optimizing media assets.


5. JavaScript Performance

Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript

Core Principle

Measure first. Use browser network and performance tools to identify what actually needs optimizing before implementing techniques.

Optimizing Downloads

  • Use minimal JavaScript -- avoid frameworks for static experiences
  • Remove unused code -- delete functionality not being used
  • Leverage built-in browser features: built-in form validation, native <video> players, CSS animations instead of JavaScript libraries
  • Minification -- reduces file character count and bytes
  • Compression -- gzip (standard) or Brotli (generally outperforms gzip)
  • Module bundlers -- use webpack for optimization and code splitting

Loading Critical Assets Early

<!-- Preload standard JavaScript -->
<link rel="preload" href="important-js.js" as="script" />

<!-- Preload JavaScript module -->
<link rel="modulepreload" href="important-module.js" />

Deferring Non-Critical JavaScript

Async:

<script async src="main.js"></script>

Defer:

<script defer src="main.js"></script>

Dynamic loading:

const scriptElem = document.createElement("script");
scriptElem.src = "index.js";
scriptElem.addEventListener("load", () => {
  init();
});
document.head.append(scriptElem);

Dynamic module import:

import("./modules/myModule.js").then((module) => {
  // Use the loaded module
});

Breaking Down Long Tasks

Tasks taking more than 50ms are "long tasks" that block the main thread. Use task yielding:

function yieldFunc() {
  if ("scheduler" in window && "yield" in scheduler) {
    return scheduler.yield();
  }
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
}

async function main() {
  const tasks = [a, b, c, d, e];
  while (tasks.length > 0) {
    const task = tasks.shift();
    task();
    await yieldFunc();
  }
}

Animation Best Practices

  • Reduce non-essential animations
  • Provide an opt-out for users on low-power devices
  • Prefer CSS animations over JavaScript (much faster and more efficient)
  • For canvas animations, use requestAnimationFrame():
function loop() {
  ctx.fillStyle = "rgb(0 0 0 / 25%)";
  ctx.fillRect(0, 0, width, height);
  for (const ball of balls) {
    ball.draw();
    ball.update();
  }
  requestAnimationFrame(loop);
}
loop();

Event Performance

  • Remove unnecessary event listeners with removeEventListener()
  • Use event delegation (single listener on parent instead of multiple on children):
parent.addEventListener("click", (event) => {
  if (event.target.matches(".child")) {
    // Handle child click
  }
});

Efficient Code Patterns

Batch DOM changes:

const fragment = document.createDocumentFragment();
for (let i = 0; i < items.length; i++) {
  const li = document.createElement("li");
  li.textContent = items[i];
  fragment.appendChild(li);
}
ul.appendChild(fragment); // Single DOM operation

Exit loops early:

for (let i = 0; i < array.length; i++) {
  if (array[i] === toFind) {
    processMatchingArray(array);
    break;
  }
}

Move work outside loops:

// Fetch once, iterate in-memory
const response = await fetch(`/results?number=${number}`);
const results = await response.json();
for (let i = 0; i < number; i++) {
  processResult(results[i]);
}

Offload Computation

  • Asynchronous JavaScript -- async/await for non-blocking I/O
  • Web Workers -- offload heavy computation to a separate thread
  • WebGPU -- use the system GPU for high-performance computations

6. CSS Performance

Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/CSS

Rendering and CSSOM Optimization

Remove unnecessary styles:

  • Parse only used CSS rules
  • Clean up unused styles added during development

Split CSS into separate modules:

<!-- Render-blocking -->
<link rel="stylesheet" href="styles.css" />

<!-- Non-blocking with media queries -->
<link rel="stylesheet" href="print.css" media="print" />
<link rel="stylesheet" href="mobile.css" media="screen and (width <= 480px)" />

Minify and compress CSS as part of the build process with gzip compression on servers.

Simplify selectors:

/* Avoid overly complex selectors */
body div#main-content article.post h2.headline {
  font-size: 24px;
}

/* Prefer simple selectors */
.headline {
  font-size: 24px;
}

Avoid universal over-application:

/* Problematic */
body * {
  font-size: 14px;
  display: flex;
}

Reduce HTTP requests with CSS sprites -- combine multiple small images into one file and use background-position.

Preload critical assets:

<link rel="preload" href="style.css" as="style" />
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />

Animation Performance

Properties that cause reflow/repaint (avoid animating):

  • Dimensions: width, height, border, padding
  • Position: margin, top, bottom, left, right
  • Layout: align-content, align-items, flex
  • Visual effects: box-shadow

Safe properties to animate (GPU-accelerated):

  • transform
  • opacity
  • filter

Respect user preferences:

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

Advanced Optimization

will-change property (use as a last resort only):

.element {
  will-change: opacity, transform;
}

CSS Containment:

article {
  contain: content;
}

content-visibility (skip rendering until needed):

article {
  content-visibility: auto;
  contain-intrinsic-size: 1000px;
}

Font Performance

Load important fonts early:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />

Load only required glyphs:

@font-face {
  font-family: "Open Sans";
  src: url("font.woff2") format("woff2");
  unicode-range: U+0025-00FF;
}

Define font display behavior:

@font-face {
  font-family: "someFont";
  src: url("font.woff") format("woff");
  font-display: fallback;
}

Font tips:

  • Use only 2-3 fonts maximum
  • Prefer web-safe fonts when possible
  • Consider rel="preconnect" for third-party font providers

7. Performance API

Source: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API

Overview

The Performance API is a group of standards used to measure web application performance. It provides built-in metrics and enables developers to add custom measurements to the browser's performance timeline with high-precision timestamps.

Available in both Window and Worker global scopes via Window.performance and WorkerGlobalScope.performance.

Core Concepts

Each performance metric is represented by a PerformanceEntry with: name, duration, startTime, and type.

Most entries are automatically recorded and accessible via:

  • Performance.getEntries()
  • PerformanceObserver (preferred method)

Main Interfaces

Performance Management:

  • Performance -- main interface for accessing performance measurements
  • PerformanceEntry -- base interface for all performance metrics
  • PerformanceObserver -- listens for new performance entries as they are recorded

Custom Measurements:

  • PerformanceMark -- custom markers on the performance timeline
  • PerformanceMeasure -- custom measurements between two entries

Built-in Metrics:

Interface Purpose
PerformanceNavigationTiming Document navigation timings (load time, etc.)
PerformanceResourceTiming Network metrics for resources (images, scripts, CSS, fetch calls)
PerformancePaintTiming Render operations during page construction
PerformanceEventTiming Event latency and Interaction to Next Paint (INP)
LargestContentfulPaint Render time of largest visible content
LayoutShift Page layout stability metrics
PerformanceLongTaskTiming Long-running tasks blocking rendering
PerformanceLongAnimationFrameTiming Long animation frame metrics
PerformanceServerTiming Server metrics from Server-Timing HTTP header

Usage Pattern

// Using PerformanceObserver (recommended)
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`${entry.name}: ${entry.duration}ms`);
  }
});
observer.observe({ entryTypes: ["navigation", "resource", "paint"] });

// Custom measurements
performance.mark("start-operation");
// ... perform work ...
performance.mark("end-operation");
performance.measure("operation-duration", "start-operation", "end-operation");

8. Performance Data

Source: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Performance_data

Types of Performance Entries

Entry Type Interface Purpose
"element" PerformanceElementTiming Load and render time for specific DOM elements
"event" PerformanceEventTiming Browser response time to event triggers
"first-input" PerformanceEventTiming First Input Delay measurement
"largest-contentful-paint" LargestContentfulPaint Largest paint during page load
"layout-shift" LayoutShift Page layout shift metrics
"longtask" PerformanceLongTaskTiming Tasks taking 50ms or more
"mark" PerformanceMark Custom developer timestamps
"measure" PerformanceMeasure Custom measurements between timestamps
"navigation" PerformanceNavigationTiming Navigation and initial page load metrics
"paint" PerformancePaintTiming Key rendering moments during page load
"resource" PerformanceResourceTiming Resource fetch duration
"visibility-state" VisibilityStateEntry Tab visibility state changes

Accessing Performance Data

Method 1: PerformanceObserver (preferred)

function logEventDuration(entries) {
  const events = entries.getEntriesByType("event");
  for (const event of events) {
    console.log(
      `Event handler took: ${event.processingEnd - event.processingStart} milliseconds`
    );
  }
}

const observer = new PerformanceObserver(logEventDuration);
observer.observe({ type: "event", buffered: true });

Advantages of PerformanceObserver:

  • Automatically filters duplicate entries
  • Asynchronous delivery during idle time
  • Required for some entry types
  • Lower performance impact

Method 2: Direct query methods

performance.getEntries();              // All entries
performance.getEntriesByType(type);    // Entries of specific type
performance.getEntriesByName(name);    // Entries with specific name

Performance Entry Buffer Sizes

Entry Type Max Buffer Size
"resource" 250 (adjustable)
"longtask" 200
"element" 150
"event" 150
"layout-shift" 150
"largest-contentful-paint" 150
"visibility-state" 50
"mark" Infinite
"measure" Infinite
"navigation" Infinite
"paint" 2 (fixed)
"first-input" 1 (fixed)

Handling Dropped Entries

function perfObserver(list, observer, droppedEntriesCount) {
  list.getEntries().forEach((entry) => {
    // process entries
  });
  if (droppedEntriesCount > 0) {
    console.warn(
      `${droppedEntriesCount} entries were dropped because the buffer was full.`
    );
  }
}
const observer = new PerformanceObserver(perfObserver);
observer.observe({ type: "resource", buffered: true });

JSON Serialization

All performance entries provide a toJSON() method:

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log(entry.toJSON());
  });
});
observer.observe({ type: "event", buffered: true });

Opt-In Metrics

Some metrics require explicit configuration:

  • Element Timing -- add elementtiming attribute to elements
  • User Timing -- call Performance API methods at relevant points
  • Server Timing -- server sends Server-Timing HTTP header

9. Server Timing

Source: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Server_timing

What is Server Timing?

Server Timing is part of the Performance API and allows servers to communicate metrics about the request-response cycle to the user agent. It surfaces backend server timing metrics such as database read/write times, CPU time, and file system access.

Server-Timing HTTP Header Examples

// Single metric without value
Server-Timing: missedCache

// Single metric with value
Server-Timing: cpu;dur=2.4

// Single metric with description and value
Server-Timing: cache;desc="Cache Read";dur=23.2

// Two metrics with values
Server-Timing: db;dur=53, app;dur=47.2

// Server-Timing as trailer
Trailer: Server-Timing
--- response body ---
Server-Timing: total;dur=123.4

Retrieving Server Metrics in JavaScript

Server timing metrics are stored as PerformanceServerTiming entries, accessed within "navigation" and "resource" performance entries via the PerformanceResourceTiming.serverTiming property.

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    entry.serverTiming.forEach((serverEntry) => {
      console.log(
        `${serverEntry.name} (${serverEntry.description}) duration: ${serverEntry.duration}`
      );
      // Logs "cache (Cache Read) duration: 23.2"
      // Logs "db () duration: 53"
      // Logs "app () duration: 47.2"
    });
  });
});

["navigation", "resource"].forEach((type) =>
  observer.observe({ type, buffered: true })
);

Privacy and Security Considerations

  • The Server-Timing header may expose sensitive application and infrastructure information; metrics should only be returned to authenticated users
  • PerformanceServerTiming is restricted to the same origin by default
  • Use the Timing-Allow-Origin header to specify allowed cross-origin domains
  • Only available in secure contexts (HTTPS) in some browsers
  • There is no clock synchronization between server, client, and intermediate proxies; server timestamps may not meaningfully map to the client timeline startTime

10. User Timing

Source: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/User_timing

Overview

User Timing is part of the Performance API and allows you to measure application performance using high-precision timestamps. It consists of two main components:

  • PerformanceMark entries -- named marks at any location in an application
  • PerformanceMeasure entries -- time measurements between two marks

Adding Performance Markers

// Basic marks
performance.mark("login-started");
performance.mark("login-finished");

// Advanced mark with options
performance.mark("login-started", {
  startTime: 12.5,
  detail: { htmlElement: myElement.id },
});

Measuring Duration Between Markers

const loginMeasure = performance.measure(
  "login-duration",
  "login-started",
  "login-finished"
);
console.log(loginMeasure.duration);

Advanced measurement from an event timestamp to a mark:

loginButton.addEventListener("click", (clickEvent) => {
  fetch(loginURL).then((data) => {
    renderLoggedInUser(data);
    const marker = performance.mark("login-finished");
    performance.measure("login-click", {
      detail: { htmlElement: myElement.id },
      start: clickEvent.timeStamp,
      end: marker.startTime,
    });
  });
});

Observing Performance Measures

function perfObserver(list, observer) {
  list.getEntries().forEach((entry) => {
    if (entry.entryType === "mark") {
      console.log(`${entry.name}'s startTime: ${entry.startTime}`);
    }
    if (entry.entryType === "measure") {
      console.log(`${entry.name}'s duration: ${entry.duration}`);
    }
  });
}
const observer = new PerformanceObserver(perfObserver);
observer.observe({ entryTypes: ["measure", "mark"] });

Retrieving Markers and Measures

// All entries
const entries = performance.getEntries();

// Filter by type
const marks = performance.getEntriesByType("mark");
const measures = performance.getEntriesByType("measure");

// Retrieve by name
const debugMarks = performance.getEntriesByName("debug-mark", "mark");

Removing Markers and Measures

// Clear all marks
performance.clearMarks();

// Remove specific mark
performance.clearMarks("myMarker");

// Clear all measures
performance.clearMeasures();

// Remove specific measure
performance.clearMeasures("myMeasure");

Advantages Over Date.now() and performance.now()

  • Meaningful names for better organization
  • Integrates with browser developer tools (Performance Panels)
  • Works seamlessly with other Performance APIs like PerformanceObserver
  • Better tooling integration overall