Web Performance Basics That Actually Matter


Most web performance advice focuses on sophisticated techniques that don’t matter until you’ve handled the basics. Here’s what actually makes sites faster, without the complexity.

Image Optimization

Images are usually the biggest files on any page. A single unoptimized photo can be larger than your entire JavaScript bundle.

Use appropriate formats. JPG for photos, PNG for graphics with transparency, WebP for everything if you can support it. WebP typically reduces file size by 25-30% compared to JPG with similar quality.

Resize images to the display size. Don’t serve 4000px wide images when your layout displays them at 800px. The browser does the resizing anyway, but downloads all those wasted pixels.

Use lazy loading for images below the fold. <img loading="lazy"> delays loading until the user scrolls near them. This works natively in modern browsers without JavaScript.

Compress images before uploading. Tools like ImageOptim or squoosh.app reduce file size without visible quality loss. This should be part of your build process, not manual work.

Minimize JavaScript

JavaScript is expensive. It has to be downloaded, parsed, compiled, and executed. Large JavaScript bundles are the most common cause of slow sites.

Audit your dependencies. Run npm ls or check your bundle analyzer. You’ll often find duplicate libraries, unused code, or massive dependencies that don’t justify their size.

Code splitting helps. Don’t send all JavaScript upfront. Split by route so users only download code for the page they’re viewing. Most bundlers support this out of the box.

Tree shaking removes unused code during builds. Make sure your bundler is configured to do this. Webpack and Rollup both support it, but you need to use ES modules syntax for it to work.

Critical CSS

CSS blocks rendering. The browser won’t display anything until it’s downloaded and parsed all stylesheets. This means external CSS files delay the entire page.

Inline critical CSS directly in the HTML. This is the CSS needed to render above-the-fold content. Everything else can load asynchronously.

Tools like Critical or Critters extract critical CSS automatically during builds. You write normal stylesheets and the build process handles inline optimization.

Remove unused CSS. Tools like PurgeCSS scan your HTML and remove styles that aren’t applied anywhere. CSS frameworks like Tailwind or Bootstrap include thousands of styles you’ll never use.

HTTP Caching

Caching prevents redownloading files that haven’t changed. Set appropriate cache headers on static assets.

Use content hashing in filenames. Instead of app.js, use app.abc123.js where the hash changes when contents change. This lets you cache aggressively while ensuring users get updates immediately.

Set long cache times for hashed files. Cache-Control: public, max-age=31536000 caches for a year. Since filenames change with content, stale caches aren’t a problem.

For HTML, use shorter cache times or validate with ETags. You want users to check for updates, but you can skip redownloading if nothing changed.

Font Loading

Web fonts are another common bottleneck. By default, browsers hide text until custom fonts load. This causes flash of invisible text (FOIT).

Use font-display: swap to show fallback fonts immediately. Text appears in a system font, then swaps to your custom font when it loads. This is better than invisible text.

Preload critical fonts. <link rel="preload" href="font.woff2" as="font"> starts downloading the font immediately, before the CSS that references it is parsed.

Subset fonts to only include needed characters. If you only use Latin characters, don’t include Cyrillic or Chinese glyphs. Tools like glyphanger or fonttools handle subsetting.

Consider variable fonts. Instead of separate files for different weights, variable fonts include a range of weights in a single file. They’re often smaller than multiple static fonts combined.

Reduce Requests

Every HTTP request has overhead: DNS lookup, TCP connection, TLS handshake, HTTP headers. Reducing requests reduces this overhead.

Combine small files when it makes sense. Inline SVG icons directly in HTML rather than loading them as separate files. Combine CSS files during builds.

Use HTTP/2 multiplexing. With HTTP/2, multiple files can download simultaneously over a single connection. This reduces the benefit of combining files, but HTTP/2 isn’t universal yet.

Consider data URIs for tiny images. Encoding small images as base64 directly in CSS eliminates HTTP requests. This only makes sense for very small images because base64 encoding increases file size.

Server Response Time

Frontend optimization doesn’t matter if the server is slow. If your Time to First Byte (TTFB) is multiple seconds, fix the backend first.

Use CDNs for static assets. CDNs serve files from servers geographically close to users. This reduces latency, especially for users far from your origin server.

Enable gzip or brotli compression on text files. This compresses HTML, CSS, and JavaScript before sending them. Most servers support this with simple configuration.

Cache dynamic content when possible. If content doesn’t change per user or changes infrequently, generate it once and serve cached copies. This applies to full pages or API responses.

Measuring Performance

Use real user metrics, not just synthetic tests. Tools like Lighthouse are useful for development, but they don’t reflect actual user experience.

Track Core Web Vitals: Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS). These correlate with user experience better than older metrics like total load time.

Measure on real devices and networks. Your development machine is faster than your users’ phones. Test on actual mobile devices with throttled connections.

Monitor performance over time. One-off audits help, but you need continuous monitoring to catch regressions. Set up automated performance budgets in your CI/CD pipeline.

What Not to Worry About

Micro-optimizations rarely matter. Shaving 50ms from a script that takes 5ms is meaningless if your images add 3 seconds to load time.

Don’t obsess over perfect scores in Lighthouse. Real user experience matters more than test scores. A site with a 95 score that loads slowly for actual users needs work.

Premature optimization wastes time. Build features first, then optimize when you have evidence of problems. Measure before optimizing.

Common Mistakes

Loading third-party scripts in the <head> that block rendering. Analytics, ads, and tracking scripts should load asynchronously or be deferred.

Not testing on slow networks. Fast connections hide performance problems. Test with throttling enabled to see what users on 3G experience.

Ignoring perceived performance. How fast something feels matters as much as actual speed. Progressive rendering, skeleton screens, and meaningful feedback make sites feel faster even when measurements don’t change.

The 80/20 Rule

Most performance gains come from a few changes: optimize images, reduce JavaScript, cache effectively, and make sure the server responds quickly. These fundamentals outweigh sophisticated techniques.

Advanced optimization matters at scale, but start with basics. Fix obvious problems before diving into complex solutions.