| @@ -114,16 +114,39 @@ | ||
| 114 | 114 | ); |
| 115 | 115 | } |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | - // CLS fix — reserve space by giving images that have neither width nor | |
| 119 | - // height their intrinsic dimensions. | |
| 120 | - if ( $this->do_dimensions | |
| 121 | - && false === stripos( $tag, 'width=' ) | |
| 122 | - && false === stripos( $tag, 'height=' ) ) { | |
| 123 | - $dim = $this->resolve_dimensions( $tag ); | |
| 124 | - if ( $dim ) { | |
| 125 | - $attrs .= ' width="' . (int) $dim[0] . '" height="' . (int) $dim[1] . '"'; | |
| 118 | + // CLS fix — make sure the image always carries BOTH width and height so the | |
| 119 | + // browser has an intrinsic aspect ratio. A missing dimension is as harmful as | |
| 120 | + // missing both: an <img> with width but no height (e.g. a block with a custom | |
| 121 | + // width) has no aspect ratio, so once core's "sizes=auto" is added the | |
| 122 | + // `contain-intrinsic-size:3000px 1500px` fallback stretches it tall. When only | |
| 123 | + // one dimension is present we derive the other from the intrinsic ratio rather | |
| 124 | + // than skipping. This runs when the dimensions feature is on OR responsive | |
| 125 | + // images are on — adding a srcset is what triggers "sizes=auto", so any image | |
| 126 | + // that gets a srcset must also carry both dimensions. | |
| 127 | + if ( $this->do_dimensions || $this->do_responsive ) { | |
| 128 | + $has_w = false !== stripos( $tag, 'width=' ); | |
| 129 | + $has_h = false !== stripos( $tag, 'height=' ); | |
| 130 | + if ( ! $has_w || ! $has_h ) { | |
| 131 | + $dim = $this->resolve_dimensions( $tag ); | |
| 132 | + if ( $dim && $dim[0] > 0 && $dim[1] > 0 ) { | |
| 133 | + if ( ! $has_w && ! $has_h ) { | |
| 134 | + $attrs .= ' width="' . (int) $dim[0] . '" height="' . (int) $dim[1] . '"'; | |
| 135 | + } elseif ( $has_w ) { | |
| 136 | + // Width present, height missing → height = width × (natH / natW). | |
| 137 | + $w = $this->get_attr( $tag, 'width' ); | |
| 138 | + if ( preg_match( '/^\d+$/', $w ) && (int) $w > 0 ) { | |
| 139 | + $attrs .= ' height="' . (int) round( (int) $w * $dim[1] / $dim[0] ) . '"'; | |
| 140 | + } | |
| 141 | + } else { | |
| 142 | + // Height present, width missing → width = height × (natW / natH). | |
| 143 | + $h = $this->get_attr( $tag, 'height' ); | |
| 144 | + if ( preg_match( '/^\d+$/', $h ) && (int) $h > 0 ) { | |
| 145 | + $attrs .= ' width="' . (int) round( (int) $h * $dim[0] / $dim[1] ) . '"'; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + } | |
| 126 | 149 | } |
| 127 | 150 | } |
| 128 | 151 | |
| 129 | 152 | // Responsive delivery — add a width-descriptor srcset + sizes so the |