Image dimension attributes (width and height) tell the browser how much space to reserve for the image before it loads. Without them, the page jumps as images render — that's CLS (Cumulative Layout Shift), one of the Core Web Vitals. Pages with missing image dimensions consistently score poorly on CLS. The fix is two extra attributes per image tag. Trivial work, significant ranking impact.
# Count img tags missing width or height curl -s https://yoursite.com/ | \ grep -oE '<img[^>]*>' | \ grep -vE 'width="[^"]+"' | wc -l curl -s https://yoursite.com/ | \ grep -oE '<img[^>]*>' | \ grep -vE 'height="[^"]+"' | wc -l
<!-- Wrong: no dimensions, causes CLS --> <img src="/hero.jpg" alt="Description"> <!-- Right: intrinsic dimensions --> <img src="/hero.jpg" alt="Description" width="1200" height="675">
Use the natural (intrinsic) pixel dimensions of the source image. Not the displayed size. Browser uses these to calculate aspect ratio and reserve space.
<img src="/hero.jpg" alt="..." width="1200" height="675"
style="max-width: 100%; height: auto;">
<style>
img {
max-width: 100%;
height: auto;
}
</style>
width="1200" height="675" attribute gives the browser the aspect ratio (16:9). CSS max-width: 100%; height: auto lets the image scale down responsively while keeping that aspect ratio. Best of both worlds: no CLS, fully responsive.
When dimensions aren't known at template render time (user-uploaded images, dynamic content), use CSS aspect-ratio to reserve space.
<!-- User-uploaded image, dimensions vary -->
<div class="user-image-wrapper">
<img src="/uploads/abc123.jpg" alt="...">
</div>
<style>
.user-image-wrapper {
aspect-ratio: 16 / 9;
background: #f0f0f0;
}
.user-image-wrapper img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
Browser reserves a 16:9 box. Image loads inside that box, scaled to fit with object-fit. Even if the image's actual dimensions differ, the box stays at 16:9 — no layout shift.
Built-in. wp_get_attachment_image() outputs width and height attributes automatically. If your theme uses bare img tags with hardcoded src, switch to the helper functions:
<!-- Bad: bare img --> <img src="<?php echo $featured_image_url; ?>" alt="..."> <!-- Good: helper function --> <?php echo wp_get_attachment_image($attachment_id, 'large'); ?> <!-- Outputs: <img width="1200" height="675" src="..." alt="..." srcset="..." sizes="..." /> -->
import Image from 'next/image';
import heroImage from './hero.jpg';
<Image src={heroImage} alt="..." />
// width and height inferred from import metadata
const sharp = require('sharp');
async function getImageDimensions(filePath) {
const meta = await sharp(filePath).metadata();
return { width: meta.width, height: meta.height };
}
// At build time, pre-compute dimensions
const { width, height } = await getImageDimensions('./public/hero.jpg');
// Store in JSON, inject into templates
const probe = require('probe-image-size');
const result = await probe('https://example.com/image.jpg');
console.log(result.width, result.height);
// Downloads just enough bytes to read dimensions, then aborts
All srcset variants should have the same aspect ratio. width and height attributes on the img refer to one variant — typically the default src.
<img src="/hero-1200.jpg"
srcset="/hero-400.jpg 400w,
/hero-800.jpg 800w,
/hero-1200.jpg 1200w,
/hero-2400.jpg 2400w"
sizes="(max-width: 800px) 100vw, 1200px"
width="1200" height="675"
alt="...">
Browser uses 1200x675 to compute aspect ratio (16:9). Whatever srcset variant ends up loading, the displayed size matches that aspect ratio. No CLS regardless of which variant is selected.
<!-- BAD: CSS won't prevent CLS --> <img src="/hero.jpg" style="width: 1200px; height: 675px"> <!-- GOOD: HTML attributes --> <img src="/hero.jpg" width="1200" height="675">
CSS doesn't apply until the CSS file loads and parses. HTML attributes are available immediately when the parser hits the img tag.
<!-- BAD --> <img width="1200px" height="675px"> <!-- GOOD --> <img width="1200" height="675">
HTML width/height attributes take unitless integer pixel values. CSS uses px units.
<!-- BAD: different aspect ratios for different sizes -->
<img src="/hero-1200.jpg"
srcset="/hero-mobile-400x600.jpg 400w,
/hero-1200x675.jpg 1200w"
width="1200" height="675">
<!-- Mobile variant is 2:3 portrait, desktop is 16:9 landscape -->
<!-- Browser uses 16:9 for space reservation regardless -->
<!-- Mobile image then renders distorted or cropped -->
All srcset variants should share aspect ratio. If you need different crops at different viewports, use picture with art direction.
<picture>
<source media="(max-width: 600px)"
srcset="/hero-mobile-400x600.jpg"
width="400" height="600">
<source media="(min-width: 601px)"
srcset="/hero-desktop-1200x675.jpg"
width="1200" height="675">
<img src="/hero-desktop-1200x675.jpg"
alt="..."
width="1200" height="675">
</picture>
Each source tag gets its own width/height. Browser picks source and reserves correct space.
Verify dimension findings and measure CLS improvement.
Run Image Audit →