Skip to content
  • FG-11
  • 8 min read
  • Last checked November 7, 2026

Slow Website? How Huge Images, Too Many Fonts and Heavy Animations Slow It Down

Many slow sites are slow by design. Find the LCP element in PageSpeed Insights, then fix the hero image, trim font files, tame sliders and animations, and stop layout shift.

Run the health check

Your site feels slow, PageSpeed Insights shows red scores, or Google Search Console reports “Poor” Core Web Vitals. Your host says the server is responding quickly. The slowness is coming from the page itself.

Not every slow site is the server’s fault. Some of the biggest slowdowns are design decisions: a hero photo several megabytes in size, eight font files, a slider loading five full-size images, a background video, or scroll animations that hide content until JavaScript runs. Design problems have design fixes, and this guide shows how to find and apply them.

What Google measures

Google’s Core Web Vitals are three measurements of real visitors’ experience. Google’s published thresholds for a “good” rating are:

  • Largest Contentful Paint (LCP), 2.5 seconds or less: how long until the biggest image or text block in the first screen appears. Hero images are the usual LCP element.
  • Interaction to Next Paint (INP), 200 milliseconds or less: how quickly the page responds when someone taps or clicks. Heavy JavaScript hurts this.
  • Cumulative Layout Shift (CLS), 0.1 or less: how much the content jumps around while loading.

Each is judged at the 75th percentile of real page visits, so most visitors, including those on slower phones, need a good experience.

Before you start

  • Access you need: WordPress admin, your page builder, an image editor or optimization plugin, and a desktop browser with developer tools.
  • Measure first. Run PageSpeed Insights (pagespeed.web.dev) on the slow page, for mobile. Save the report so you can compare after each change.
  • Know the two kinds of data. The top section shows field data from real Chrome users over the previous 28 days, if your site has enough traffic. The lower section is a lab test run once on a simulated phone. Lab results update immediately; field data takes weeks to reflect a fix.
  • Where the code goes. Nothing in this guide runs in a terminal. The <img> example shows what to look for in the Elements panel of developer tools. <link rel="preload"> lines belong in the page’s <head>: use your builder’s or theme’s setting for custom head code, or a header code plugin. CSS blocks go in your builder’s global custom CSS or your theme’s custom CSS.

Step 1: Find the LCP element

In the PageSpeed Insights report, look in the diagnostics for the Largest Contentful Paint element (newer versions show it under an LCP breakdown insight). It names the exact element, usually a hero image, a background image or a large heading, and splits the time into phases. A long “load delay” means the browser discovered the image late. A long “load duration” means the file is too big.

Step 2: Fix the hero image

If the LCP element is an image, it is usually the single biggest win.

Serve the right size

Check the image’s displayed width in developer tools (hover over it in the Elements panel) and compare it with the file’s real width. A 6000-pixel camera photo shown at 1400 pixels wastes most of its bytes. Export at about the displayed width, or up to twice that for high-density screens, and no larger.

Use a modern format

WebP is supported by all current browsers and is typically much smaller than JPEG at similar quality. AVIF is often smaller still. WordPress has supported AVIF uploads since version 6.5, provided your server’s image library supports it. An image optimization plugin can convert existing uploads.

Let the browser choose with srcset

When you insert an image from the media library as a normal image, WordPress adds srcset and sizes attributes automatically, listing several sizes so phones download a smaller file. CSS background images get none of this. They also cannot be discovered until the CSS has loaded, which adds delay. For a hero, prefer a real image element positioned behind the content over a background image.

Never lazy-load the LCP image

Lazy loading (loading="lazy") delays images until they are about to scroll into view. That is right for images further down, but on the hero it makes the browser wait. Check the hero’s HTML in developer tools:

<img src="hero-1600.webp" srcset="..." sizes="100vw"
     width="1600" height="900" alt="..."
     fetchpriority="high">

This is an example of good markup to compare against, not code to paste; the file name and sizes are made up. It should have no loading="lazy", and ideally fetchpriority="high", which tells the browser to download it first. WordPress adds this automatically to the image it judges most likely to be the LCP element (since version 6.3), but page builders, sliders and lazy loading plugins can override it. Most lazy loading plugins and builders have a setting to exclude the first images or specific classes.

If the hero must stay a CSS background, preload it in the page head so the browser finds it early:

<link rel="preload" as="image" href="/wp-content/uploads/hero-1600.webp" fetchpriority="high">

Replace the href value with the address of your own hero image: copy it from the Network tab (filter by Img) or from the File URL field in the media library. Add it only to the page that uses that image, or every page downloads it.

Step 3: Cut the font files

Every font family, weight and style is a separate file. A design using three families in four weights each, plus italics, can easily request a dozen files before any text settles. Open the Network tab, filter by Font, reload and count.

  • Limit families and weights. Two families and three or four weights cover most designs. Remove the rest in your builder’s typography settings or font plugin.
  • Use WOFF2, the most compressed format, supported by every current browser.
  • Subset fonts to the characters you need. A Latin-only file is far smaller than one with Cyrillic, Greek and Vietnamese.
  • Consider a variable font, where one file contains every weight. It pays off when you use three or more weights.
  • Self-host on your own domain, which avoids an extra connection to another server.
  • Preload only the one or two fonts used in the first screen:
<link rel="preload" href="/fonts/brand-sans-latin.woff2" as="font" type="font/woff2" crossorigin>

Replace the href value with the address of your own font file, copied from the Network tab with the Font filter on. Add one line per font file, for one or two files at most. Keep as="font", type="font/woff2" and crossorigin as they are. The crossorigin attribute is required for font preloads even on your own domain, otherwise the browser downloads the font twice. Make sure each @font-face rule includes font-display: swap, so text appears in a fallback font immediately instead of staying invisible.

Icon fonts deserve a look too. Loading a complete icon library to show five icons costs a large file and a render delay. Inline SVG icons are lighter.

Step 4: Tame sliders, video backgrounds and animation

  • Hero sliders load several large images plus a JavaScript library, and the first slide is often built by JavaScript, which delays LCP. A single strong image usually loads faster and, in many cases, communicates better.
  • Background videos can be several megabytes. If you keep one, compress it hard, keep it short and muted, give it a lightweight poster image, and consider showing only the poster on phones.
  • Entrance animations that fade in the hero heading or image keep the LCP element invisible until the animation finishes, which counts against you. Do not animate anything in the first screen on load.
  • Animation libraries loaded for a few effects add JavaScript that hurts INP. Builders often include built-in animations that are lighter than an extra library.

When you do animate, animate only transform and opacity. The browser can handle those without recalculating the layout. Animating width, height, top, left or margin forces layout work on every frame and causes stutter on phones. And respect visitors who ask their operating system for less motion:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Paste this block as shown into your site-wide custom CSS; there is nothing to change. It only takes effect for visitors who have turned on reduced motion in their device settings.

Step 5: Stop layout shift

Content that jumps as the page loads is measured by CLS. The usual design causes:

  • Images without dimensions. Give every image width and height attributes (WordPress does for media library images) or a CSS aspect-ratio, so the browser reserves the space before the file arrives.
  • Embeds and widgets (videos, maps, reviews, booking forms) that appear late. Wrap them in a container with a fixed aspect ratio or minimum height.
  • Banners inserted at the top, such as cookie notices or announcement bars that push content down. Overlay them at the bottom of the screen instead.
  • Font swaps where the fallback font is much wider or narrower than the brand font, so text reflows when the font arrives. Choose a fallback with similar proportions; the size-adjust descriptor in @font-face can fine-tune it.

Step 6: Audit third-party scripts

Chat widgets, tag managers, heatmaps, social feeds, ad scripts and multiple analytics tools each add JavaScript that competes with your page, and they are a common cause of poor INP. In PageSpeed Insights, check the third-party section to see what each one costs. Remove anything nobody looks at. For the rest, load chat widgets and video embeds only when a visitor clicks (a static placeholder that loads the real thing on click), and avoid running two analytics tools that do the same job.

Check your work

After each change, purge your caches and rerun PageSpeed Insights. Lab scores vary a little between runs, so compare a few runs rather than one. Field data in PageSpeed Insights and Search Console uses a rolling 28-day window, so expect real-user numbers to improve gradually over the following weeks.

When it is not the design

If PageSpeed Insights shows a slow server response time (the time before the first byte arrives), the bottleneck is on the server: slow plugins, missing page caching, an overloaded plan or slow database queries. Ask your host to look at it, and send them the URL, the PageSpeed Insights report, and the times you saw the slowness.

Still stuck?

Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.

Get the free checklists

Keep reading

All field guides

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close