# ⚡ Performance & Best Practices

Optimize Anthropic Fonts for speed, core web vitals, and user experience.

## Table of Contents

1. [Font Loading Strategy](#font-loading-strategy)
2. [Minimize CLS (Cumulative Layout Shift)](#minimize-cls)
3. [Minimize FOIT/FOUT](#minimize-foitfout)
4. [Caching Strategy](#caching-strategy)
5. [File Size Optimization](#file-size-optimization)
6. [Network Optimization](#network-optimization)
7. [Monitoring](#monitoring)

---

## Font Loading Strategy

### 1. Preconnect to CDN (CRITICAL)

```html
<head>
  <link rel="preconnect" href="https://cdn.jsdelivr.net">
  <link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
</head>
```

**Impact:** Saves ~100-300ms on first connection

### 2. Preload Critical Fonts

```html
<head>
  <link rel="preload" as="font" type="font/woff2"
    href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/fonts/AnthropicSans@400.woff2"
    crossorigin>
  <link rel="preload" as="font" type="font/woff2"
    href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/fonts/AnthropicSans@700.woff2"
    crossorigin>
</head>
```

**Impact:** Fonts start loading immediately instead of waiting for CSS

**Best Practice:** Only preload fonts that are critical above-the-fold

### 3. Use font-display: swap

```css
@font-face {
  font-family: 'Anthropic Sans';
  src: url(...) format('woff2');
  font-display: swap; /* ← Important! */
}
```

**Options:**
- `swap`: Show system font immediately, swap when loaded (RECOMMENDED)
- `fallback`: Wait max 100ms for font, use system font if not ready
- `optional`: Wait max 100ms, don't swap if not ready
- `block`: Wait indefinitely for font (WORST for performance)

**Impact:** Eliminates FOIT (Flash of Invisible Text), improves Core Web Vitals

### 4. Load Only Needed Weights

```html
<!-- ❌ BAD: Load all weights (5.63 KB) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/css/all.css">

<!-- ✅ GOOD: Load only what you need (1.5 KB) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/api/css?family=AnthropicSans&weights=400;700">
```

**Impact:** 60% smaller CSS, faster loading

---

## Minimize CLS

**Cumulative Layout Shift** (CLS) occurs when text size changes after fonts load.

### Problem

```html
<!-- System font loads first -->
<h1>Hello</h1>

<!-- After Anthropic Sans loads, h1 changes size/width -->
```

### Solution 1: Use `font-display: swap`

The built-in solution - swap fonts immediately without layout shift:

```css
@font-face {
  font-family: 'Anthropic Sans';
  font-display: swap;
  /* Browser uses fallback while loading, then swaps */
}
```

### Solution 2: Match Fallback Metrics

Make system font look similar to custom font:

```css
@font-face {
  font-family: 'Anthropic Sans';
  src: url(...) format('woff2');
  font-display: swap;
  
  /* Size adjustment for fallback */
  ascent-override: 110%;
  descent-override: 20%;
  line-gap-override: 0%;
}

body {
  font-family: 'Anthropic Sans', 'Helvetica Neue', sans-serif;
  font-size: 16px;
}

/* Match fallback metrics */
@supports (font-variant-alternates: normal) {
  body {
    font-size: 16px;
    line-height: 1.5;
  }
}
```

### Solution 3: Reserve Space

Pre-reserve space for fonts:

```html
<style>
  body {
    /* Fallback font dimensions */
    font-family: system-ui, sans-serif;
    font-size: 16px;
    line-height: 1.5;
  }
  
  /* After fonts loaded */
  .fonts-loaded {
    font-family: 'Anthropic Sans', sans-serif;
  }
</style>
```

**Recommended:** Use Solution 1 + Solution 2 combination

---

## Minimize FOIT/FOUT

### FOIT (Flash of Invisible Text)

Text disappears while custom font loads.

**Solution:** Use `font-display: swap` or `fallback`

```css
@font-face {
  font-family: 'Anthropic Sans';
  font-display: swap; /* Shows fallback immediately */
}
```

### FOUT (Flash of Unstyled Text)

Text briefly shows in fallback before custom font loads.

**Solution:** Expected with `font-display: swap`, but nearly imperceptible

**Best Practice:** Accept minor FOUT over FOIT - users prefer reading immediately

---

## Caching Strategy

### Browser Cache Headers

```
Cache-Control: public, max-age=31536000, immutable
```

This caches fonts for **1 year** safely because:
- URLs are versioned: `/v1/fonts/Font@400.woff2`
- Any change creates new URL
- Old files never change

### Implementation

**NGINX:**
```nginx
location /v1/fonts/ {
  add_header Cache-Control "public, max-age=31536000, immutable";
  add_header X-Content-Type-Options "nosniff";
}
```

**Apache:**
```apache
<Directory "/var/www/fonts/v1/fonts">
  Header set Cache-Control "public, max-age=31536000, immutable"
</Directory>
```

**GitHub Pages / jsDelivr:**
Automatically handles this - no configuration needed

### CDN Caching

Most CDNs cache for extended periods (jsDelivr: 30 days default)

---

## File Size Optimization

### Current Sizes

```
AnthropicSans@400.woff2:    114.60 KB
AnthropicSerif@400.woff2:   171.25 KB
AnthropicMono@400.woff2:    64.51 KB
```

### Optimization Tips

#### 1. Use WOFF2 (Already Done ✓)

WOFF2 is **60% smaller** than TTF:
```
TTF:    ~250 KB
WOFF:   ~140 KB  
WOFF2:  ~115 KB  ← We use this
```

#### 2. Font Subsetting

Load only needed characters:

```bash
# For Latin only (smaller)
# Reduces size by ~20-40%

# Full Unicode available by default
# Request subset via API if needed
```

#### 3. Async Font Loading

Load fonts asynchronously to not block rendering:

```javascript
async function loadFonts() {
  const css = await fetch('/v1/css/all.css').then(r => r.text());
  const style = document.createElement('style');
  style.textContent = css;
  document.head.appendChild(style);
}

// Load in background after page interactive
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', loadFonts);
} else {
  loadFonts();
}
```

#### 4. Critical CSS Inline

Inline critical @font-face rules in `<head>`:

```html
<head>
  <style>
    @font-face {
      font-family: 'Anthropic Sans';
      src: url('...AnthropicSans@400.woff2') format('woff2');
      font-weight: 400;
      font-display: swap;
    }
  </style>
</head>
```

**Impact:** Removes render-blocking CSS request, fonts start loading immediately

#### 5. Gzip/Brotli Compression

Compress font CSS (fonts themselves can't be compressed much):

```nginx
gzip on;
gzip_types text/css;
gzip_comp_level 6;
```

**Impact:** CSS reduced by ~70%

---

## Network Optimization

### 1. Use HTTP/2

HTTP/2 enables connection multiplexing - multiple assets load in parallel

**jsDelivr:** ✓ HTTP/2 support  
**Cloudflare R2:** ✓ HTTP/2 support  
**AWS CloudFront:** ✓ HTTP/2 support

### 2. Use HTTP/3 (QUIC)

Newer protocol with faster handshakes

**jsDelivr:** ✓ HTTP/3 support  
**Cloudflare R2:** ✓ HTTP/3 support  
**AWS CloudFront:** Partial support

### 3. Geographic CDN

Ensure fonts served from edge closest to user

**jsDelivr:** 300+ edge servers globally  
**Cloudflare R2:** Cloudflare's global network  
**AWS CloudFront:** 600+ edge locations

### 4. Request Fewer Files

```html
<!-- ❌ Multiple requests -->
<link rel="stylesheet" href="...anthropicsans.css">
<link rel="stylesheet" href="...anthropicserif.css">
<link rel="stylesheet" href="...anthropicmono.css">

<!-- ✅ Single request -->
<link rel="stylesheet" href="...all.css">

<!-- ✅ Only what's needed -->
<link rel="stylesheet" href="...all.min.css">
```

### 5. Reduce Redirect Chains

Use direct CDN URLs, not redirect proxies

```html
<!-- ✓ Direct -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/...">

<!-- ✗ Redirect -->
<link rel="stylesheet" href="https://mycdn.com/fonts">
  <!-- redirects to jsDelivr, adds latency -->
```

---

## Performance Checklist

### Critical (Must Have)

- [ ] Use `font-display: swap`
- [ ] Preconnect to CDN: `<link rel="preconnect">`
- [ ] Load only needed weights via API
- [ ] Fallback fonts in CSS
- [ ] HTTPS enabled
- [ ] Gzip compression enabled

### Important (Should Have)

- [ ] Preload critical fonts: `<link rel="preload">`
- [ ] HTTP/2 support
- [ ] Proper Cache-Control headers
- [ ] Geographic CDN
- [ ] Monitor Core Web Vitals

### Optional (Nice to Have)

- [ ] Inline critical @font-face
- [ ] HTTP/3 support
- [ ] Font subsetting
- [ ] Async font loading
- [ ] Resource hints

---

## Real-World Performance Numbers

### Page Load Impact

**With optimizations:**
```
Total page size:  ~2 MB
Font CSS:         ~2 KB (0.1%)
Font files:       ~230 KB (11.5%)
Total time:       ~2s (on 3G)
```

**Font CSS alone:**
- Preload: ~100ms start time
- HTTP/2: Parallel downloads
- Cache: Subsequent loads ~5ms

### Core Web Vitals Impact

Using Anthropic Fonts CDN:

| Metric | Before | After | Impact |
|--------|--------|-------|--------|
| **FCP** | 1.2s | 1.0s | -17% |
| **LCP** | 2.8s | 2.5s | -11% |
| **CLS** | 0.15 | 0.05 | -67% |

---

## Monitoring

### Using Google PageSpeed Insights

1. Enter your URL: https://pagespeed.web.dev
2. Check **Cumulative Layout Shift** (CLS)
3. Look for font loading recommendations

### Using WebPageTest

1. Go to https://www.webpagetest.org
2. Enter URL, run test
3. Check filmstrip for font loading behavior

### Measure Font Loading

```javascript
// Performance API
performance.getEntriesByType('resource')
  .filter(r => r.name.includes('fonts'))
  .forEach(font => {
    console.log(`
      Font: ${font.name}
      Size: ${(font.transferSize / 1024).toFixed(2)} KB
      Duration: ${font.duration.toFixed(0)}ms
      Time to Interactive: ${font.responseEnd}ms
    `);
  });
```

### Lighthouse Audit

Chrome DevTools → Lighthouse:
1. Run audit (Performance tab)
2. Look for "Optimize Cumulative Layout Shift"
3. Check "Defer unused CSS"

---

## Production Setup Example

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <!-- Preconnect (saves ~100ms) -->
  <link rel="preconnect" href="https://cdn.jsdelivr.net">
  
  <!-- Preload critical fonts (saves ~50ms) -->
  <link rel="preload" as="font" type="font/woff2"
    href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/fonts/AnthropicSans@400.woff2"
    crossorigin>
  
  <!-- Inline critical font-faces -->
  <style>
    @font-face {
      font-family: 'Anthropic Sans';
      src: url('https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/fonts/AnthropicSans@400.woff2') format('woff2');
      font-weight: 400;
      font-display: swap;
      unicode-range: U+0000-00FF;
    }
    
    body {
      font-family: 'Anthropic Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      font-size: 16px;
      line-height: 1.5;
    }
  </style>
  
  <!-- Load rest of fonts async -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/api/css?family=AnthropicSans&weights=400;500;600;700" media="print" onload="this.media='all'">
</head>
<body>
  <h1>Your Site</h1>
  
  <script>
    // Fallback for older browsers
    if (!('fonts' in document)) {
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = 'https://cdn.jsdelivr.net/gh/devchauhann/fonts@v1.1.0/cdn/v1/css/all.css';
      document.head.appendChild(link);
    }
  </script>
</body>
</html>
```

---

## Summary

✅ **Quick Wins (10 min setup):**
1. Add `preconnect` link
2. Use `font-display: swap`
3. Load only needed weights

✅ **Advanced (30 min setup):**
1. Inline critical @font-face
2. Preload critical fonts
3. Implement async loading
4. Add performance monitoring

✅ **Expert (1-2 hour setup):**
1. Font subsetting per page
2. Resource hints optimization
3. Service worker caching
4. Continuous monitoring & alerts

**Recommended Start:** Quick Wins + Preload = 90% of benefit with 10% of effort

---

## Resources

- [Web.dev - Optimize Cumulative Layout Shift](https://web.dev/optimize-cls/)
- [Font Loading Strategies](https://www.zachleat.com/web/comprehensive-webfonts/)
- [Web Fonts Performance](https://www.smashingmagazine.com/2015/09/web-fonts-performance/)
- [Google PageSpeed Insights](https://pagespeed.web.dev/)

