{"id":"8pytnomdk0r7em5","title":"How to Make Your Website Load Before Your Visitors Can Blink","slug":"how-to-make-your-website-load-before-your-visitors-can-blink","summary":"Fast loading comes from a long list of small, disciplined choices: image sizes, render path, caching, JavaScript weight, fonts, and server response. There is no single magic switch.","imageUrl":"https://briancrabtree.me/images/journal-how-to-make-your-website-load-before-your-visitors-can-blink.webp","category":"UX Theory","date":"2025-12-22","featured":false,"likes":44,"author":"Brian Crabtree","content":"<h2>The Business of Speed</h2>\n\n<p>Let’s strip away the marketing fluff about \"delighting users\" and look at the brutal reality of the economics involved here. The modern user has the attention span of a gnat and the patience of a saint who has run out of miracles. When a user clicks a link, they are entering a contract with you where they trade their attention for your content, and if you make them wait more than a second, you are in breach of contract. Every millisecond of latency is a leak in your revenue funnel. I have sat in countless meetings where stakeholders agonize over the shade of blue on a call-to-action button while ignoring the fact that the page takes six seconds to become interactive on a 4G connection. If the user bounces before the button even renders, the color doesn't matter. Performance is the only feature that matters when the alternative is the user leaving entirely.</p>\n\n<p>Google understands this better than most, which is why they stopped asking nicely and started penalizing slow sites. Core Web Vitals are not just arbitrary metrics invented to torture developers; they are a direct response to the bloated mess the web has become. Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) are quantifyable measures of how annoying your site is to use. If your content jumps around while it loads because you didn't reserve space for your ads or images, you deserve the SEO penalty you are going to get. Search engines are in the business of serving answers, and if your answer is stuck behind a loading spinner, Google will route traffic to a competitor who respects the physics of data transfer. This is not about chasing an arbitrary score on a Lighthouse report; it is about ensuring your digital footprint is visible in an increasingly hostile environment.</p>\n\n<pre><code>&lt;link rel=\"preload\" href=\"/fonts/hero.woff2\" as=\"font\" crossorigin&gt;\n&lt;img src=\"/hero.webp\" width=\"800\" height=\"450\" fetchpriority=\"high\" alt=\"\"&gt;</code></pre>\n\n<h2>Physics and The Edge</h2>\n\n<p>The speed of light is a hard limit that no amount of clever coding can bypass, which brings us to the architecture of delivery. If your server is in Virginia and your user is in Tokyo, you are fighting a losing battle against latency from the moment the TCP handshake begins. The traditional model of a centralized origin server is archaic for serving anything other than highly specific, non-cacheable data. We need to stop thinking about CDNs as dumb buckets for JPEGs and start treating them as the primary runtime environment for our applications. The logic needs to live where the user lives.</p>\n\n<p>Modern edge networks like Cloudflare or Fastly have evolved far beyond simple static caching. We are talking about edge-native compute where we can execute logic within milliseconds of the user. This is where you should be handling your A/B testing, your authentication routing, and your request sanitation. Why force a request to travel halfway around the world just to be redirected? By using strategies like Stale-While-Revalidate, we can serve a cached version of the content instantly while fetching the fresh data in the background. The user gets immediate feedback, and the system eventually becomes consistent. It is a slight trade-off in strict consistency for a massive gain in perceived performance, and for 99% of web content, that is a trade you should make every single day. Using surrogate keys to surgically invalidate cache tags means we can cache dynamic content aggressively and only purge the specific bits that change, effectively turning your dynamic site into a static one for the vast majority of requests.</p>\n\n<h2>The Mobile Tax</h2>\n\n<p>There is a dangerous misconception among developers who work on $3,000 MacBook Pros that everyone else experiences the web the same way they do. We sit in our air-conditioned offices with gigabit ethernet and test our sites on the latest iPhone, completely detached from the reality of the average user. The average user is on a three-year-old Android device with a degrading battery, trying to load your site over a congested LTE network while riding a bus. When you ship a 5MB JavaScript bundle, you aren't just taking up bandwidth; you are monopolizing the main thread of their CPU. You are literally heating up their phone and draining their battery to parse your code.</p>\n\n<p>Mobile performance is about more than just responsive design and media queries. It is about CPU economy. The parsing and execution cost of JavaScript is the single biggest bottleneck on mobile devices today. A budget Android phone takes significantly longer to parse a megabyte of JS than a high-end laptop, introducing massive input delays. If your site looks loaded but doesn't respond when the user taps a button because the main thread is locked up hydrating a massive React tree, the site is broken. We have to stop treating mobile devices like miniature desktops and start treating them like constrained environments where every CPU cycle is precious.</p>\n\n<h2>The JavaScript Bloat</h2>\n\n<p>The root of all evil in modern web performance is our addiction to JavaScript. We have convinced ourselves that we need a complex Single Page Application (SPA) architecture for a blog or a marketing site that barely has any state to manage. We import massive libraries to handle simple tasks that the browser can now do natively. Do you really need a 30kb library to format a date? Do you need Lodash to filter an array? Browsers are incredibly capable pieces of software now; learn the standard APIs and stop reaching for NPM every time you encounter a minor inconvenience.</p>\n\n<p>The most performant code is the code you do not write, and the second most performant is the code you delete. Tree-shaking is a band-aid, not a cure. The solution is to architect for lightness from the start. If you are building a content-heavy site, look at islands architecture or partial hydration techniques where you only ship JavaScript for the interactive components, leaving the rest as static HTML. Tools like Astro or 11ty are a breath of fresh air because they default to zero JavaScript. If you must use a framework, choose one that respects the wire weight. Preact or SolidJS can often drop in as replacements for heavier alternatives with minimal refactoring, instantly shaving precious kilobytes off your initial load.</p>\n\n<h2>Asset Hygiene</h2>\n\n<p>Beyond the code itself, we are terrible at managing the media we serve. I still see PNGs being used for photographs and massive JPEGs that haven't been compressed. There is absolutely no excuse for not using modern formats like WebP or AVIF, which offer superior compression at a fraction of the size. The browser support is there; the tooling is there. It is pure laziness to serve legacy formats to modern browsers. Furthermore, the practice of lazy-loading images should be standard, but implemented correctly. Don't just slap a loading attribute on everything; ensure you are reserving the layout space with aspect-ratio CSS properties so the page doesn't jump around like a nervous teenager while the assets populate.</p>\n\n<p>Typography is another area where vanity kills performance. I see designers insisting on loading five different weights of a custom font, plus italics, adding hundreds of kilobytes of blocking resources just so the headers look slightly different than the system default. Unless your typography is the core of your brand identity, system fonts are faster, more legible, and require zero network requests. If you must use custom fonts, subset them to include only the characters you actually use and host them yourself to avoid the DNS lookup penalty of a third-party host.</p>\n\n<h2>Cutting Through the Noise</h2>\n\n<p>Optimizing for the web is not about adding more tools to your stack; it is about taking things away. It is about ruthless prioritization. It is about understanding that every byte you send down the wire has a cost attached to it—a cost in latency, in processing power, and in user patience. The tools we have today, from WebPageTest to the Chrome DevTools performance profiler, give us microscopic visibility into where our sites are failing. Use them. Don't just run a Lighthouse audit and pat yourself on the back for a green score; look at the waterfall chart. Look at the long tasks. Understand the critical rendering path.</p>\n\n<p>We need to return to a mindset of scarcity. Build as if you are paying for every byte out of your own pocket. Because in a way, you are. You are paying for it in server costs, in lost conversions, and in the erosion of your brand's reputation. A fast website is the ultimate sign of respect for your users. It says that you value their time more than you value your own developer experience. It is time to stop hiding behind loading spinners and start shipping software that works. For a related angle I keep coming back to, see <a href=\"/journal/why-pagespeed-scores-change-every-run/\">Why PageSpeed Scores Change Every Run (And What to Fix First)</a>.</p>","tags":["Server-Side Rendering (SSR)","Next.js App Router","TypeScript Static Analysis","WebAssembly Performance Optimization","Containerization with Docker Compose"],"views":100}