Skip to main content Skip to content

Faster WordPress: images, CSS and JavaScript

When a WordPress site feels slow, the cause is most often what the browser has to fetch and process: large images, stylesheets that block rendering, and JavaScript from the theme and plugins that loads on every single page. Most of it can be fixed without changing theme or hosting. Here we go through images, CSS, JavaScript and fonts in the order they typically give the most, and how to measure whether it works.

This guide is about what happens in the browser. The server, the database and PHP are the other half, and we cover that in the guide to how WordPress delivers a page.

What Google measures: Core Web Vitals

Google measures the user experience with three numbers, and they’re a good starting point for setting priorities:

MetricWhat it measuresGood valueTypical cause of problems
LCP (Largest Contentful Paint)When the largest element at the top is shown2.5 seconds at mostLarge images, blocking CSS, a slow server
INP (Interaction to Next Paint)How quickly the page responds to clicks200 milliseconds at mostHeavy JavaScript
CLS (Cumulative Layout Shift)How much the content jumps around0.1 at mostImages without dimensions, fonts that swap

The thresholds come from Google’s documentation on web.dev. They’re measured on real visitors, so a page can score well on your own computer and still be slow for customers on mobile.

Images: the biggest and easiest place to start

On most pages, images are the largest part of what has to be downloaded, which is why image optimization often gives the most for the least work. Start with the format. WebP and AVIF produce much smaller files than JPEG and PNG at the same quality, all modern browsers support them, and WordPress can handle both if the server can. An optimization plugin or your CDN can convert existing images and send the best format to each browser.

Next, the size. An image 4,000 pixels wide shown at 800 wastes bandwidth. WordPress creates several sizes of every image itself and lets the browser pick the smallest one that fits, but only if the theme uses WordPress’s own image functions. Never upload images straight from the camera.

Lazy loading is the third piece: WordPress waits to fetch images further down until they’re about to come into view. That’s good, but not for the top image. The hero or product image at the top is usually the page’s LCP element and should be fetched right away, ideally with high priority. WordPress tries to get this right itself, but page builders and themes often break it, so check it in the browser’s developer tools. And make sure every image has dimensions, so space is reserved for it and the text doesn’t jump when it arrives.

CSS: show the page before everything is loaded

The browser shows nothing until every stylesheet in <head> has been fetched and read. Many WordPress sites load CSS from the theme, the page builder and every single plugin on every page, including where the plugin isn’t used at all.

Critical CSS

Critical CSS is the small part of your CSS needed to show what you see without scrolling. It’s placed directly in <head>, while the rest is loaded without blocking, so the page can be shown right away. It’s almost always generated by a tool or a performance plugin, because it differs from template to template. Test thoroughly afterwards: wrong critical CSS causes a brief flash of unstyled content.

Load only what the page uses

The biggest gain is often removing CSS that isn’t used. A contact form plugin doesn’t need its stylesheet on the product pages. Some plugins can turn it off themselves; otherwise an asset manager plugin can remove files per page, or you can do it in the theme:

add_action( 'wp_enqueue_scripts', function () {
    // Only on the contact page
    if ( ! is_page( 'contact' ) ) {
        wp_dequeue_style( 'contact-form-7' );
    }
}, 20 );

Minification is almost always an advantage, but bundling everything into one big file no longer is. With HTTP/2, the browser can fetch many files in parallel, and a huge file has to be downloaded again every time a small part changes. Read more about what HTTP/3 changes for your site’s speed.

JavaScript: less, later and only where it’s needed

Byte for byte, JavaScript is more expensive than images, because the browser doesn’t just have to fetch it but also run it, and while it does, the page can’t respond to clicks. Heavy JavaScript is therefore the typical cause of a poor INP. If you’re not a developer, start with our introduction: JavaScript explained for website owners.

Async and defer

An ordinary script in <head> stops the browser until it has been fetched and run. With defer, the script is fetched in the background and only run once the HTML has been read, in the order the scripts appear. That’s the safe choice for most scripts. With async, the script runs as soon as it’s fetched, regardless of order, which suits standalone scripts like analytics tools. Since WordPress 6.3 you can set the strategy directly, and WordPress makes sure a script isn’t deferred if another script depends on it:

wp_enqueue_script(
    'my-theme',
    get_theme_file_uri( 'assets/js/theme.js' ),
    array(),
    '1.0.0',
    array( 'strategy' => 'defer', 'in_footer' => true )
);

Load scripts only where they’re used

As with CSS, the biggest gain is avoiding scripts the page doesn’t use. Use wp_enqueue_script conditionally with functions like is_product() or has_block(), and remove plugins’ scripts with wp_dequeue_script where they aren’t needed. Go through your plugins: every plugin that adds JavaScript to every page costs a little on every single page view.

Third-party scripts

Chat widgets, social widgets, heatmaps and ad scripts are often the heaviest scripts on a page, and you have no control over them. Ask for each one whether it’s necessary, and whether it can wait until the page is shown or the user interacts. Some performance plugins can delay specific scripts until the user scrolls or clicks.

For online stores

WooCommerce and its extensions add scripts for the cart, variations, payment and tracking. Check which of them load on pages where nobody is shopping, such as blog posts, and be careful about deferring scripts in the cart and checkout. Test the whole purchase flow after every change.

Fonts

Every weight and style of a web font is a file that has to be downloaded, so keep it to a couple of weights. Host the fonts yourself, so the browser doesn’t have to open an extra connection, use font-display: swap so text is shown right away, and preload only the fonts used at the top of the page. A fallback font of the same size stops the text from jumping when the web font arrives.

How to measure whether it works

PageSpeed Insights shows both a lab test and, if the page has enough traffic, Core Web Vitals from real users, and Search Console shows them for the whole site grouped by page type. If you want to see exactly which files are fetched and what’s blocking, the Network and Performance tabs in the browser’s developer tools are the best place. Measure before and after every change, test on mobile with a throttled connection, and make one change at a time, so you know what helped.

The order we’d do it in

  1. Measure the page, and find the LCP element and the heaviest files.
  2. Optimize images: format, size and lazy loading, but not on the LCP image.
  3. Remove CSS and JavaScript from pages where they aren’t used, and remove plugins you don’t need.
  4. Add defer to your own scripts, and delay third-party scripts.
  5. Add critical CSS, and test every page type.
  6. Clean up the fonts.
  7. Measure again, and repeat.

Frequently asked questions

Why is my site slow even though I have fast hosting?

Hosting only decides how fast the server responds. If the browser then has to download several megabytes of images and run heavy JavaScript, the page is slow anyway.

Can optimization break something?

Yes. Deferred JavaScript and wrong critical CSS are the typical causes of menus that don’t work and content that flickers. Test after every change, and for an online store, always all the way through cart and payment.

Want help?

We measure, find the bottlenecks and fix them across the front end, server and database, so your store gets fast without anything breaking. Get your store made faster.

← All articles

Want help with your store?

Is your store slow, unstable or just hard to work with? Write a few lines and a link, and you'll get an honest assessment from the developer.