---
title: "Fix Incorrect Image Aspect Ratio for Better Best Practices Score"
description: "Display images with their natural aspect ratio to prevent distortion. Stretched or squished images look unprofessional."
canonical_url: "https://unlighthouse.dev/learn-lighthouse/best-practices/image-aspect-ratio"
last_updated: "2025-01-18"
---

When an image's display dimensions don't match its natural aspect ratio, it gets stretched or squished. Faces look wrong. Products look unprofessional. Users notice.

## What's Happening

You have an image with natural dimensions of 1200x800 (aspect ratio 1.5:1), but you're displaying it at 400x400 (aspect ratio 1:1). The browser has three choices: stretch it, squish it, or crop/contain it. Without explicit `object-fit` instructions, it stretches.

Lighthouse compares the displayed aspect ratio to the natural aspect ratio. If they differ by more than a couple pixels (accounting for rounding), the audit fails. It only checks images using `object-fit: fill` (the default) because other values intentionally override aspect ratio behavior.

## Diagnose

### Chrome DevTools

1. Right-click the distorted image, select **Inspect**
2. Check the element's rendered dimensions vs natural dimensions:

```js
// Select the image element first
const img = $0
console.log({
  natural: `${img.naturalWidth}x${img.naturalHeight}`,
  displayed: `${img.clientWidth}x${img.clientHeight}`,
  naturalRatio: (img.naturalWidth / img.naturalHeight).toFixed(2),
  displayedRatio: (img.clientWidth / img.clientHeight).toFixed(2)
})
```

If the ratios don't match, that's your problem.

### Find All Distorted Images

```js
document.querySelectorAll('img').forEach((img) => {
  if (!img.naturalWidth || !img.naturalHeight)
    return
  if (img.clientWidth < 5 || img.clientHeight < 5)
    return

  const naturalRatio = img.naturalWidth / img.naturalHeight
  const displayedRatio = img.clientWidth / img.clientHeight
  const diff = Math.abs(naturalRatio - displayedRatio)

  if (diff > 0.05) {
    console.warn('Aspect ratio mismatch:', img.src, {
      natural: `${img.naturalWidth}x${img.naturalHeight} (${naturalRatio.toFixed(2)})`,
      displayed: `${img.clientWidth}x${img.clientHeight} (${displayedRatio.toFixed(2)})`
    })
  }
})
```

## Fix

### 1. Match Container to Image Ratio

The cleanest fix: make the display dimensions match the natural aspect ratio.

```html
<!-- Image is 1200x800 (1.5:1 ratio) -->
<!-- Bad: forcing into a square -->
<img src="/photo.jpg" style="width: 400px; height: 400px;">

<!-- Good: maintaining ratio -->
<img src="/photo.jpg" style="width: 400px; height: 267px;">

<!-- Better: let height auto-calculate -->
<img src="/photo.jpg" width="1200" height="800" style="width: 400px; height: auto;">
```

With `width` and `height` attributes, browsers calculate the aspect ratio automatically:

```css
img {
  max-width: 100%;
  height: auto;
}
```

### 2. Use object-fit for Fixed Containers

When you need a specific container size regardless of image ratio, use `object-fit`:

```css
.thumbnail {
  width: 200px;
  height: 200px;
  object-fit: cover; /* Crop to fill, maintain ratio */
}

.product-image {
  width: 100%;
  height: 300px;
  object-fit: contain; /* Fit inside, maintain ratio, may letterbox */
}
```

**object-fit values:**

- `cover` - Fill container, crop excess (most common for thumbnails)
- `contain` - Fit inside container, letterbox if needed
- `fill` - Stretch to fill (default, causes distortion)
- `none` - Natural size, crop if larger
- `scale-down` - Like `contain` but never upscales

```html
<div class="avatar">
  <img src="/user.jpg" alt="User" style="width: 100%; height: 100%; object-fit: cover;">
</div>
```

```css
.avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  overflow: hidden;
}
```

### 3. Use aspect-ratio for Responsive Containers

Let CSS maintain the ratio while the container scales:

```css
.video-thumbnail {
  width: 100%;
  aspect-ratio: 16 / 9;
}

.video-thumbnail img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
```

The container maintains 16:9, and `object-fit: cover` handles any image that doesn't match exactly.

### 4. Crop Images at Source

If every image in a gallery should be square, crop them to square before uploading rather than relying on CSS:

```js
// Server-side with Sharp
import sharp from 'sharp'

sharp('input.jpg')
  .resize(400, 400, {
    fit: 'cover',
    position: 'attention' // Smart crop
  })
  .toFile('output-square.jpg')
```

This gives you control over what gets cropped rather than leaving it to CSS.

## Framework Examples

<callout icon="i-logos-nuxt-icon">

**Nuxt** - Use `NuxtImg` with `fit` prop:

```html
<template>
  <NuxtImg
    src="/photo.jpg"
    width="400"
    height="400"
    fit="cover"
    alt="Photo"
  />
</template>
```

For containers with fixed aspect ratio:

```html
<div class="aspect-square">
  <NuxtImg src="/photo.jpg" class="w-full h-full object-cover" />
</div>
```

</callout>

<callout icon="i-logos-nextjs-icon">

**Next.js** - `next/image` with `fill` and `objectFit`:

```jsx
<div className="relative w-48 h-48">
  <Image
    src="/photo.jpg"
    fill
    style={{ objectFit: 'cover' }}
    alt="Photo"
  />
</div>
```

For responsive with maintained ratio:

```jsx
<Image
  src="/photo.jpg"
  width={1200}
  height={800}
  style={{ width: '100%', height: 'auto' }}
  alt="Photo"
/>
```

</callout>

## Verify the Fix

1. **Visual check** - Images should look natural, not stretched or squished
2. **Re-run Lighthouse** - "Displays images with correct aspect ratio" should pass
3. **Console check:**

```js
document.querySelectorAll('img').forEach((img) => {
  const style = getComputedStyle(img)
  if (style.objectFit !== 'fill')
    return // Using cover/contain is fine

  const naturalRatio = img.naturalWidth / img.naturalHeight
  const displayedRatio = img.clientWidth / img.clientHeight
  if (Math.abs(naturalRatio - displayedRatio) > 0.05) {
    console.warn('Still distorted:', img.src)
  }
})
```

## Common Mistakes

- **Setting only width** - `width: 100%` without `height: auto` causes stretching if there's an inherited height.
- **Forgetting object-fit on avatars** - Circle avatars with square images need `object-fit: cover` or they'll oval.
- **Wrong width/height attributes** - If your HTML says 400x300 but the image is 1200x800, browsers use the attributes for ratio calculation. Make them match.
- **Background images** - This audit only checks `<img>` elements. Distorted background images need `background-size: cover` or `contain`.

## Test Your Entire Site

Your homepage might look perfect while product pages stretch images into a grid. [Unlighthouse](/) checks every page and surfaces all distorted images across your entire site.
