Your Site Isn’t Slow — Your First Paint Is

Every conversation about a slow website starts in the wrong place: the host, the theme, the page builder, the age of the server. All of those can matter. Almost none of them are what a visitor actually experiences.

A visitor experiences the gap between “something appeared” and “I gave up.” That gap has a name — first contentful paint — and on most modern sites it is manufactured by the page itself, not by the server. The server can answer in 200ms and the visitor can still stare at white for two seconds, because everything after the HTML arrives is your own page blocking its own render.

Measure the gap before you optimize anything

Open the site, open DevTools, and get two numbers: how long the server took to answer, and how long until the first pixel of content appeared. The Network waterfall shows both and answers the question in about ten seconds. The Performance panel records it properly if you want the version you can defend.

Those two numbers diagnose almost everything:

  • Both slow. You have a server problem. Caching, queries, hosting, or a plugin doing something expensive on every request.
  • Server fast, first paint slow. You have a page problem, and it lives in the head of the document: stylesheets, fonts, scripts, and the order they have to arrive in.
  • First paint fast, page still feels broken. Different bug entirely. That is layout shift — images without dimensions, banners injecting themselves late, a font swapping and reflowing the paragraph under the cursor.

A real example from this week: 268ms to first byte, 422ms to DOM ready, and 1500ms before anything was visible. The HTML arrived fast and then sat there.

First paint is not the whole of Core Web Vitals — largest contentful paint and interaction to next paint matter too — but it is the one the visitor notices first, and on a badly built page it is the one that decides whether they stay.

The usual suspects, in order of payoff

  • No page cache. If every visit boots PHP, every visit is a fresh coin flip. A page cache is the biggest single lever, and it is not “install and forget” — you have to confirm it is actually serving, because a cache that silently missed looks exactly like no cache at all. That one change took a site from a 4.8s first paint to 1.5s.
  • Render-blocking CSS and JS. Count the <link rel="stylesheet"> tags in your page source. If there are twenty, the browser has twenty obligations to settle before it paints anything. Most are plugins loading on pages that never use them. Generate critical CSS for the above-the-fold region, defer the rest, and then check that the generator actually produced output — the feature is only worth the checkbox when it wrote the file.
  • Fonts without display=swap. Text stays invisible until the webfont lands, so a 300ms font request becomes a 300ms blank page. One parameter in the font URL — or font-display: swap in the @font-face — and the text renders in the fallback, then swaps. Keep only the weights you actually set in type: a six-weight webfont is half a megabyte of typography nobody asked for.
  • Assets enqueued once and loaded everywhere. A store plugin’s stylesheet on the homepage, a slider library on a page with no slider, an embed script for a service you do not use. Find them in the waterfall and stop loading them — wp_dequeue_style() and wp_dequeue_script() on the templates that never needed them. This is the least glamorous item on the list and the most common reason a simple page makes forty requests.
  • Everything stacked on one connection at a time. Confirm HTTP/2 or HTTP/3 is on so parallel requests multiplex instead of queueing, then count how many tools are watching the same visitor: three tag managers, two chat widgets, a heatmap, a session recorder. Each one is a script someone else’s server has to answer before your page is allowed to appear.

What actually changed

Cache on, and confirmed serving. Fonts trimmed to the weights actually in use, with swap. One plugin’s worth of assets removed from pages that never rendered them. Same HTML, same content, same design — and a page that paints in a fraction of the time.

None of that was a server upgrade. It was refusing to let a page load things it does not use.

The part nobody wants to hear

Stop optimizing against the lab score. A Lighthouse run on a fast desktop with an empty cache is a measurement of a machine, not of a user on a phone in an elevator. Load your own homepage on a throttled connection — DevTools, Network, Fast 3G, cache disabled — and watch the waterfall instead of the dial. The waterfall tells you what is blocking and in what order; the dial only tells you whether you are winning at a number.

A site that scores 100 and takes three seconds to show a headline is still a site that takes three seconds to show a headline.

If your site takes longer to appear than it takes to read the first paragraph, the problem is in the head of your document, not in the datacenter.



Leave a Reply

This website uses cookies and asks your personal data to enhance your browsing experience. We are committed to protecting your privacy and ensuring your data is handled in compliance with the General Data Protection Regulation (GDPR).