# All images have explicit width and height attributes

- **Pattern:** `ab-001791` (`marketing-page-speed.resource-optimization.image-dimensions-reserved`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001791
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001791)

## Why it matters

An `<img>` tag without `width` and `height` attributes is a direct cause of Cumulative Layout Shift — the browser allocates zero space for the image before it loads, then expands the layout when the dimensions are known, shifting every element below it. This is a mechanical cause of CLS as measured under ISO-25010 time-behaviour, not a heuristic concern. Marketing pages with feature grids, testimonial carousels, and team sections frequently contain dozens of images, each a potential layout shift event. A CLS score above 0.1 classifies the page as 'needs improvement' in Core Web Vitals, which reduces the page experience signal Google uses for search ranking decisions.

## Severity rationale

Medium because missing image dimensions mechanically cause layout shifts that degrade CLS scores, but the ranking impact is bounded to pages with significant above-fold image content.

## Remediation

Add explicit `width` and `height` to every `<img>` tag — the browser uses the aspect ratio these provide to reserve the correct space before the image loads.

```tsx
// Before — browser allocates no space, shifts layout on load
<img src="/feature-icon.svg" alt="Feature" />

// After — browser reserves the correct height before download
<img src="/feature-icon.svg" alt="Feature" width={48} height={48} />

// Next.js fill mode — parent must have an explicit height
<div style={{ position: 'relative', height: '400px', width: '100%' }}>
  <Image src="/photo.webp" alt="Photo" fill style={{ objectFit: 'cover' }} />
</div>
```

For responsive images where the display size varies, set `width` and `height` to the intrinsic image dimensions — CSS can scale the element down without causing CLS because the aspect ratio is already known.

## Detection

- **ID:** `image-dimensions-reserved`
- **Severity:** `medium`
- **What to look for:** Check every `<img>` tag and Image component across marketing page components. Every image without explicit `width` and `height` causes layout shift as the browser doesn't know how much space to reserve before the image loads. This is a direct contributor to CLS scores. Check for: bare `<img>` tags, `<Image>` without dimensions, `fill` mode on Next.js Image (acceptable only when parent container has explicit dimensions). Count all instances found and enumerate each.
- **Pass criteria:** Every `<img>` tag has `width` and `height` attributes. Next.js `<Image>` components have `width` and `height` props (required by the component). When `fill` is used, the parent container has explicit dimensions via CSS. At least 1 implementation must be confirmed.
- **Fail criteria:** Any `<img>` tag missing `width` and/or `height`. Next.js Image using `fill` without an explicit-height parent container.
- **Skip (N/A) when:** No images used in the project.
- **Detail on fail:** `"FeatureSection.tsx has 4 <img> tags without width/height. TestimonialGrid.tsx uses <Image fill> with a parent container that has no explicit height — both cause CLS."`
- **Remediation:** Add dimensions to every image:

  ```tsx
  // Before — CLS risk
  <img src="/feature-icon.svg" alt="Feature" />

  // After — dimensions reserved
  <img src="/feature-icon.svg" alt="Feature" width={48} height={48} />

  // Next.js fill mode — parent must have explicit height
  <div style={{ position: 'relative', height: '400px' }}>
    <Image src="/photo.webp" alt="Photo" fill objectFit="cover" />
  </div>
  ```

## External references

- iso-25010 performance-efficiency.time-behaviour

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-001791
