Skip to main content

ByUpdated

Performance Optimization

Make your BiModal site fast for humans and efficient for agents

Performance is a feature. Fast sites provide better user experiences, rank higher in search results, and are more accessible to users on slow connections. BiModal Design naturally leads to better performance through server-side rendering and progressive enhancement, but optimization ensures you maximize these benefits.

Performance Fundamentals

<2.5s

Target LCP

Largest Contentful Paint - main content should load in under 2.5 seconds

<100ms

Target INP

Interaction to Next Paint - pages should respond to user input quickly

<0.1

Target CLS

Cumulative Layout Shift - minimize unexpected layout changes

The Performance Hierarchy

Optimize in this order for maximum impact:

  1. 1
    Rendering Strategy - Server-side rendering vs client-side (biggest impact)
  2. 2
    Image Optimization - Images are typically 50-70% of page weight
  3. 3
    Caching - Cache effectively, serve content faster
  4. 4
    JavaScript - Minimize and defer non-critical JS
  5. 5
    CSS Optimization - Critical CSS inline, defer the rest

Rendering Strategy

Your rendering strategy has the biggest impact on performance. BiModal Design strongly favors server-side rendering.

Server-Side Rendering

Immediate Content: HTML contains all content, visible instantly
Better Core Web Vitals: LCP, FCP, and TTI all significantly better
Works Without JS: Content accessible even if JS fails or is disabled
Agent-Friendly: Agents can read everything in initial HTML
SEO Advantages: Search engines see full content immediately

Client-Side Rendering

Blank Page: Users see nothing until JS downloads and executes
Poor Core Web Vitals: High LCP, delayed FCP, slow TTI
JS Required: Site breaks if JavaScript fails to load
Agent-Invisible: Most agents don't execute JS, see empty page
SEO Challenges: Search engines may not index dynamic content

Recommended Frameworks (SSR-First)

Next.js

React with SSR, app router supports streaming SSR

Remix

Full-stack React framework, SSR by default

SvelteKit

Svelte with SSR, excellent performance

Astro

Static-first, ships zero JS by default

Nuxt

Vue with SSR, universal rendering

Eleventy

Static site generator, extremely fast

Image Optimization

Images typically account for 50-70% of page weight. Optimizing them has massive impact.

Use Modern Image Formats

<!-- Serve WebP/AVIF with fallback -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description" width="800" height="600">
</picture>
AVIF: ~50% smaller than JPEG, best quality
WebP: ~30% smaller than JPEG, wide support
JPEG/PNG: Fallback for older browsers

Responsive Images

<!-- Serve appropriate size for device -->
<img
  src="image-800.jpg"
  srcset="
    image-400.jpg 400w,
    image-800.jpg 800w,
    image-1200.jpg 1200w,
    image-1600.jpg 1600w
  "
  sizes="(max-width: 640px) 100vw,
         (max-width: 1024px) 50vw,
         800px"
  alt="Description"
  width="800"
  height="600"
>

Impact: Mobile users download 400px images instead of 1600px, reducing payload by 75% or more.

Lazy Loading

<!-- Native lazy loading -->
<img
  src="image.jpg"
  alt="Description"
  loading="lazy"
  width="800"
  height="600"
>

<!-- Eager load above-the-fold images -->
<img
  src="hero.jpg"
  alt="Hero image"
  loading="eager"
  width="1600"
  height="900"
>

loading="lazy": Defers loading until image is near viewport

loading="eager": Loads immediately (default, use for above-fold)

Browser support: 97%+ of browsers support native lazy loading

Priority Hints

<!-- High priority for LCP image -->
<img
  src="hero.jpg"
  alt="Hero"
  fetchpriority="high"
  width="1600"
  height="900"
>

<!-- Low priority for below-fold images -->
<img
  src="footer-logo.png"
  alt="Logo"
  fetchpriority="low"
  loading="lazy"
>

Image Optimization Checklist

CSS Optimization

Critical CSS

Inline CSS needed for above-the-fold content, defer the rest.

<!DOCTYPE html>
<html>
<head>
  <!-- Critical CSS inline -->
  <style>
    /* Only styles needed for above-the-fold content */
    body { margin: 0; font-family: system-ui; }
    .header { background: #fff; padding: 1rem; }
    .hero { min-height: 400px; }
  </style>

  <!-- Defer non-critical CSS -->
  <link
    rel="stylesheet"
    href="/styles.css"
    media="print"
    onload="this.media='all'"
  >
  <noscript>
    <link rel="stylesheet" href="/styles.css">
  </noscript>
</head>

Tools: Use tools like Critical, Critters, or PurgeCSS to extract critical CSS automatically.

CSS Best Practices

1. Minimize CSS Size
  • • Remove unused CSS with PurgeCSS or similar
  • • Use CSS minification in production
  • • Consider utility-first CSS (Tailwind) to avoid bloat
2. Avoid @import

@import blocks parallel downloads. Use <link> tags or bundle CSS instead.

3. Use Efficient Selectors

Avoid complex selectors like .header nav ul li a. Use single class names when possible.

4. Leverage CSS Containment
/* Isolate component rendering */
.card {
  contain: layout style paint;
}

JavaScript Optimization

BiModal Principle:

The best JavaScript is no JavaScript. Only send JS that enhances an already-working site.

Code Splitting

Split JavaScript into smaller chunks, load only what's needed.

// Dynamic import - loads only when needed
button.addEventListener('click', async () => {
  const { initModal } = await import('./modal.js');
  initModal();
});

// React lazy loading
const Modal = lazy(() => import('./Modal'));

// Next.js dynamic import
const DynamicComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <p>Loading...</p>
});

Defer and Async Scripts

<!-- Defer: Download in parallel, execute after HTML parsing -->
<script src="/app.js" defer></script>

<!-- Async: Download and execute ASAP, may block parsing -->
<script src="/analytics.js" async></script>

<!-- Regular: Blocks HTML parsing (avoid) -->
<script src="/blocking.js"></script>
Use defer for:
  • • App functionality
  • • UI enhancements
  • • Scripts that depend on DOM
Use async for:
  • • Analytics
  • • Ads
  • • Independent scripts

Tree Shaking & Dead Code Elimination

// Use ES modules for tree shaking
import { specific, functions } from 'library';

// Avoid importing entire libraries
import _ from 'lodash'; // ✗ Imports everything (70KB+)
import debounce from 'lodash/debounce'; // ✓ Only what's needed (2KB)

JavaScript Optimization Checklist

Caching Strategies

Effective caching dramatically reduces server load and improves user experience.

HTTP Cache Headers

Static assets (JS, CSS, images with hashed names)
Cache-Control: public, max-age=31536000, immutable
HTML pages
Cache-Control: public, max-age=0, must-revalidate
API responses
Cache-Control: private, max-age=300, stale-while-revalidate=60

Pro tip: Use fingerprinted filenames (app-abc123.js) for assets, then cache them forever. When you update the file, the name changes.

Content Delivery Network (CDN)

CDNs cache content at edge locations worldwide, reducing latency.

Cloudflare

Free tier, easy setup, global coverage

Fastly

High performance, instant purging

AWS CloudFront

Integrates with AWS services

Service Workers (Advanced)

Enable offline support and advanced caching strategies.

// Basic service worker for caching
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then((cache) => {
      return cache.addAll([
        '/',
        '/styles.css',
        '/app.js',
      ]);
    })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

Font Optimization

System Fonts First

/* Use system fonts - zero download */
body {
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    sans-serif;
}

Best for performance: System fonts load instantly and look native on each platform. Consider using them for body text.

Web Fonts (When Needed)

<!-- Preload critical fonts -->
<link
  rel="preload"
  href="/fonts/heading-bold.woff2"
  as="font"
  type="font/woff2"
  crossorigin
>

<!-- Use font-display -->
<style>
@font-face {
  font-family: 'Heading';
  src: url('/fonts/heading-bold.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately */
  font-weight: 700;
}
</style>

font-display: swap - Shows fallback font immediately, swaps when custom font loads

font-display: optional - Use custom font only if it loads very quickly

Use WOFF2 format - Best compression, supported by all modern browsers

Performance Monitoring

Continuous monitoring helps you catch performance regressions early.

Real User Monitoring (RUM)

Measure actual performance experienced by real users.

Google Analytics 4: Tracks Core Web Vitals automatically
SpeedCurve: RUM with detailed waterfall charts
Sentry: Performance monitoring with error tracking

Synthetic Monitoring

Automated tests from fixed locations and conditions.

Lighthouse CI: Run Lighthouse in your CI pipeline
WebPageTest: Detailed performance analysis
PageSpeed Insights: Google's testing tool

Set Up Alerts

Configure alerts when Core Web Vitals exceed thresholds. Catch regressions before users are affected.

Performance Budget

Set limits on page weight and metrics to prevent performance regressions.

Recommended Budgets

MetricBudgetWhy
Total Page Size<1.5 MBLoads in ~5s on 3G
JavaScript<300 KBParse + execute time
CSS<100 KBFast initial render
Images<1 MBMajority of page weight
Fonts<100 KBUsually 2-3 font files
LCP<2.5sCore Web Vitals target
Total Blocking Time<200msResponsive to input
Enforce budget in CI (example with bundlesize)
// package.json
{
  "bundlesize": [
    {
      "path": "./dist/app.js",
      "maxSize": "300 KB"
    },
    {
      "path": "./dist/styles.css",
      "maxSize": "100 KB"
    }
  ]
}

🎉 Congratulations!

You've reached the end of the BiModal Design guide. You now have everything you need to build fast, accessible, agent-friendly websites.

Quick Performance Wins

  • ✓ Use server-side rendering
  • ✓ Optimize images (WebP, lazy loading)
  • ✓ Implement proper caching
  • ✓ Defer non-critical JavaScript
  • ✓ Inline critical CSS
  • ✓ Use system fonts when possible
  • ✓ Set performance budgets
  • ✓ Monitor Core Web Vitals