PageSpeed Insights Performance Issues

Practical tips for understanding and fixing common PageSpeed Insights diagnostics.

PageSpeed Insights surfaces a mix of opportunities (things you can fix to speed up the page) and diagnostics (things worth checking that don’t always have a direct score impact, like accessibility). Below are the issues we see most often, what they mean, and how to fix them.

Opportunities

🔺 Largest Contentful Paint image was lazily loaded

Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. Learn more about optimal lazy loading. LCP

loading="lazy" tells the browser it’s safe to defer a resource until it’s needed — but the browser doesn’t know in advance which image will become the LCP element. If you lazy-load an image that turns out to be above the fold, the browser delays fetching it until it’s already scrolled the DOM and computed layout, adding a completely avoidable round-trip to your LCP. Never lazy-load the hero image or any image likely to be above the fold; mark it loading="eager" (or fetchpriority="high") instead. Reserve loading="lazy" for images that are actually below the fold.

🔺 Image elements do not have explicit width and height

Set an explicit width and height on image elements to reduce layout shifts and improve CLS. CLS

Without a width/height (or CSS aspect-ratio), the browser doesn’t know how much space to reserve for an image before it loads. As the image arrives, surrounding content jumps to make room — a layout shift that hurts both CLS and the user’s experience. Always set the image’s intrinsic dimensions (or an aspect-ratio) so the browser can reserve the correct space up front. visionary-image does this automatically using the dimensions encoded in the Blurhash URL.

🔺 Eliminate render-blocking resources

Resources are blocking the first paint of your page. Consider delivering critical JS/CSS inline and deferring all non-critical JS/styles. LCP FCP

Any stylesheet or synchronous script the browser encounters before it can paint extends the critical render path. Fix this by inlining the small amount of CSS needed above the fold, loading the rest asynchronously, and adding defer or async to scripts that don’t need to run before first paint.

🔺 Reduce unused CSS

Reduce unused rules from stylesheets and defer CSS not used for above-the-fold content to decrease bytes consumed by network activity. LCP FCP

This usually comes from shipping a single global stylesheet (or a full component library’s CSS) to every page. Split styles per route where practical, remove dead rules, and let a bundler tree-shake unused CSS modules.

🔺 Reduce unused JavaScript — Potential savings of 21 KiB

Reduce unused JavaScript and defer loading scripts until they are required to decrease bytes consumed by network activity. LCP FCP

Code-split by route so pages only load the JavaScript they actually run, lazy-load below-the-fold widgets (modals, carousels, chat widgets), and audit third-party scripts — analytics and embed snippets are frequent offenders.

🟨 Properly size images

Serve images that are appropriately-sized to save cellular data and improve load time. LCP

Serving a 2000px-wide image into a 400px-wide container wastes bytes the browser has to download before it can paint. Request an image at (or slightly above, for high-DPI screens) its rendered size — this is exactly what visionary-image handles automatically via responsive srcset generation.

🟨 Serve images in next-gen formats

Image formats like WebP and AVIF often provide better compression than PNG or JPEG, which means faster downloads and less data consumption.

Re-encode images as WebP or AVIF, or use an image CDN that negotiates format automatically based on the Accept header. Both typically cut 25–50% off the file size of an equivalent-quality JPEG with no visible difference.

🟨 Serve static assets with an efficient cache policy

A long cache lifetime can speed up repeat visits to your page.

Set a long max-age (and immutable) on fingerprinted static assets — JS/CSS bundles, fonts, and images with a content hash in the filename — since the filename changes whenever the content does. There’s no reason for a returning visitor’s browser to re-fetch a file it already has.

🔺 Avoid large layout shifts

These DOM elements contribute most to the Cumulative Layout Shift of the page. CLS

Layout shift almost always comes from content that has no reserved space before it loads: images without a width/height (or aspect-ratio), web fonts that swap in and reflow text, ads or embeds injected into the flow, or content inserted above existing content. Reserve space up front — set explicit dimensions on images, use font-display: optional or preload critical fonts, and reserve a slot for dynamically-injected content.

Accessibility diagnostics

🔺 Image elements do not have [alt] attributes

Informative elements should aim for short, descriptive alternate text. Decorative elements can be ignored with an empty alt attribute.

Make sure every <img> (or visionary-image) has an alt attribute. Describe what the image conveys — not just “image” or the filename. Purely decorative images should use alt="" so screen readers skip them instead of announcing something meaningless.

🔺 Buttons do not have an accessible name

When a button doesn’t have an accessible name, screen readers announce it as “button”, making it unusable for users who rely on screen readers.

This commonly happens with icon-only buttons (a close “×”, a hamburger menu, a trash icon) that have no visible text. Add an aria-label describing the action:

<button aria-label=“Close dialog”><XIcon /></button>

Link text (and alternate text for images, when used as links) that is discernible, unique, and focusable improves the navigation experience for screen reader users.

Avoid generic link text like “click here” or “read more” with no surrounding context, and avoid links whose only content is an icon with no aria-label. Every link should make sense read on its own, since that’s how many screen reader users navigate a page — by tabbing between links.

🔺 Heading elements are not in a sequentially-descending order

Properly ordered headings that do not skip levels convey the semantic structure of the page, making it easier to navigate and understand when using assistive technologies.

Headings should form an outline — an <h2> shouldn’t be followed directly by an <h4> with no <h3> in between. Pick heading levels based on document structure, not font size; style visual size with CSS instead of by skipping levels.

Further reading