Missing Image Dimensions
Loading a moving truck without knowing how big the furniture is? That's what happens when images lack width and height attributes.
What is this?
Imagine you are loading a moving truck but you have no idea how big each piece of furniture is. You cannot plan where anything goes, so every time a new piece arrives you have to rearrange everything. That is exactly what happens when your images lack width and height attributes. The browser does not know how much space to reserve, so it shifts your entire layout around as each image loads. This jarring effect is called Cumulative Layout Shift (CLS).
Why it matters
- For your visitors: They start reading a paragraph, an image loads above it, and suddenly the text they were reading jumps down the page. They lose their place, accidentally click the wrong link, or just get annoyed. On mobile, this is especially infuriating because the viewport is smaller and every pixel of shift is noticeable.
- For your business: CLS is one of Google's three Core Web Vitals. A high CLS score directly hurts your search rankings. It also tanks trust — visitors who experience layout shifts perceive your site as broken or unfinished.
- The standard: Every
<img>element should include explicitwidthandheightattributes (or be sized via CSS aspect-ratio). Google recommends a CLS score under 0.1 for a "good" user experience.
<img src="/hero.webp" alt="Product screenshot" width="1200" height="630" /><img src="/hero.webp" alt="Product screenshot" />How to fix it
React / Next.js
Next.js has a built-in Image component that handles dimensions automatically when you use static imports. For remote images, you must provide width and height explicitly.
import Image from "next/image";
import heroImg from "@/assets/hero.webp"; // static import — dimensions auto-detected
// Static import: dimensions come from the file itself
<Image src={heroImg} alt="Product screenshot" />
// Remote image: you must specify dimensions
<Image
src="https://example.com/photo.jpg"
alt="Team photo"
width={800}
height={450}
/>
// Fill mode: when you want the image to fill its container
<div className="relative h-64 w-full">
<Image
src="https://example.com/banner.jpg"
alt="Banner"
fill
className="object-cover"
/>
</div>If you are using regular <img> tags in React, always include the attributes:
function Avatar({ src, name }: { src: string; name: string }) {
return <img src={src} alt={`${name}'s avatar`} width={48} height={48} className="rounded-full" />;
}Plain HTML
Add width and height attributes to every image. These set the aspect ratio — CSS can still control the actual rendered size.
<!-- The browser reserves the correct space before the image loads -->
<img
src="/product.webp"
alt="Product photo"
width="600"
height="400"
style="max-width: 100%; height: auto;"
/>
<!-- For responsive images, the aspect-ratio property also works -->
<style>
.hero-img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
</style>
<img src="/hero.webp" alt="Hero banner" class="hero-img" />Layout shift is one of the most annoying things a visitor can experience. The cat hates surprises, and so do your visitors. Always declare your dimensions.
How the cat scores this
The scanner checks every <img> element for explicit width and height attributes or a CSS aspect-ratio declaration. Images without either get flagged. The severity scales with how many dimensionless images appear above the fold — a missing dimension on a hero image is a much bigger problem than on a footer thumbnail. The scanner also checks for Next.js Image components missing their width/height or fill props.
Further reading
- web.dev: Optimize CLS — Google's comprehensive guide to fixing layout shift
- MDN: img width and height attributes — the HTML spec for image dimensions
- Next.js Image component — automatic image optimization in Next.js
Heavy Inline Styles
Writing the dress code on every single wedding invitation individually? That's what inline styles do to your page. Here's a better way.
Missing Lazy Loading
Downloading every episode of a show before watching episode 1? That's your page loading all images at once. Lazy load them instead.