ByJoel GoldfootUpdated
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.
Jump to Section:
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:
- 1Rendering Strategy - Server-side rendering vs client-side (biggest impact)
- 2Image Optimization - Images are typically 50-70% of page weight
- 3Caching - Cache effectively, serve content faster
- 4JavaScript - Minimize and defer non-critical JS
- 5CSS 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
✗Client-Side Rendering
Recommended Frameworks (SSR-First)
React with SSR, app router supports streaming SSR
Full-stack React framework, SSR by default
Svelte with SSR, excellent performance
Static-first, ships zero JS by default
Vue with SSR, universal rendering
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>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
- • Remove unused CSS with PurgeCSS or similar
- • Use CSS minification in production
- • Consider utility-first CSS (Tailwind) to avoid bloat
@import blocks parallel downloads. Use <link> tags or bundle CSS instead.
Avoid complex selectors like .header nav ul li a. Use single class names when possible.
/* 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>- • App functionality
- • UI enhancements
- • Scripts that depend on DOM
- • 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
Cache-Control: public, max-age=31536000, immutableCache-Control: public, max-age=0, must-revalidateCache-Control: private, max-age=300, stale-while-revalidate=60Pro 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.
Free tier, easy setup, global coverage
High performance, instant purging
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.
Synthetic Monitoring
Automated tests from fixed locations and conditions.
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
| Metric | Budget | Why |
|---|---|---|
| Total Page Size | <1.5 MB | Loads in ~5s on 3G |
| JavaScript | <300 KB | Parse + execute time |
| CSS | <100 KB | Fast initial render |
| Images | <1 MB | Majority of page weight |
| Fonts | <100 KB | Usually 2-3 font files |
| LCP | <2.5s | Core Web Vitals target |
| Total Blocking Time | <200ms | Responsive to input |
// 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