Repository: GoogleChrome/lighthouse (JavaScript)

Issue:
Image aspect ratio test is too strict?
### FAQ

- [X] Yes, my issue is not about [variability](https://github.com/GoogleChrome/lighthouse/blob/main/docs/variability.md) or [throttling](https://github.com/GoogleChrome/lighthouse/blob/main/docs/throttling.md).
- [X] Yes, my issue is not about a specific accessibility audit (file with [axe-core](https://github.com/dequelabs/axe-core) instead).

### URL

https://www.call4drinks.de/c/Cola-Colamixgetr%C3%A4nke

### What happened?

Testing the above URL it says the product image ratios are incorrect:

Original: 63 x 256 (0.25)
Shown: 32 x 128 (0.25)


Its impossible to scale the original image correctly since the original width is 63 pixel which is not dividable without fractional part.

The image aspect ratio should be aware of this. If the rounded aspect ratio with 2 fractional digits of original and shown image are equal it should be measured equal and correct.

The original aspect ratio in this example is: 0.24609 rounded to 0.25

![google pagespeed - image aspect ratio](https://github.com/GoogleChrome/lighthouse/assets/5265550/66e96bb2-f811-4dfe-8d79-bdab76f6c4b8)

### What did you expect?

The aspect ratios of 0.25 are identical so the test result is not correct.

### What have you tried?

_No response_

### How were you running Lighthouse?

PageSpeed Insights

### Lighthouse Version

10.3.0

### Chrome Version



_No response_

### Node Version

_No response_

### OS

_No response_

### Relevant log output

_No response_





Discussion:

Patch:
diff --git a/core/audits/image-aspect-ratio.js b/core/audits/image-aspect-ratio.js
index e0fe13070cd2..259dd5d40dcd 100644
--- a/core/audits/image-aspect-ratio.js
+++ b/core/audits/image-aspect-ratio.js
@@ -59,7 +59,16 @@ class ImageAspectRatio extends Audit {
     const displayedAspectRatio = image.displayedWidth / image.displayedHeight;
 
     const targetDisplayHeight = image.displayedWidth / actualAspectRatio;
-    const doRatiosMatch = Math.abs(targetDisplayHeight - image.displayedHeight) < THRESHOLD_PX;
+    const targetDisplayWidth = image.displayedHeight * actualAspectRatio;
+
+    // Small rounding errors in aspect ratio can lead to large differences in target width/height
+    // if the aspect ratio is close to 0.
+    //
+    // In these cases, we should compare the smaller dimension because any rounding errors will
+    // affect that dimension less.
+    const doRatiosMatch = targetDisplayHeight < targetDisplayWidth
+      ? Math.abs(targetDisplayHeight - image.displayedHeight) < THRESHOLD_PX
+      : Math.abs(targetDisplayWidth - image.displayedWidth) < THRESHOLD_PX;
 
     return {
       url,


Test patch:
diff --git a/core/test/audits/image-aspect-ratio-test.js b/core/test/audits/image-aspect-ratio-test.js
index 8f548f9254e2..2657f04687e2 100644
--- a/core/test/audits/image-aspect-ratio-test.js
+++ b/core/test/audits/image-aspect-ratio-test.js
@@ -100,7 +100,7 @@ describe('Images: aspect-ratio audit', () => {
     },
   });
 
-  testImage('is almost the right aspect ratio', {
+  testImage('is almost the right expected height', {
     score: 1,
     clientSize: [412, 36],
     naturalSize: [800, 69],
@@ -109,6 +109,15 @@ describe('Images: aspect-ratio audit', () => {
     },
   });
 
+  testImage('is a small aspect ratio with a rounding error', {
+    score: 1,
+    clientSize: [63, 256],
+    naturalSize: [32, 128],
+    props: {
+      isCss: false,
+    },
+  });
+
   testImage('aspect ratios match', {
     score: 1,
     clientSize: [100, 100],