craft-imageoptimize
craft-imageoptimize copied to clipboard
More robust output for art-direction use cases
Is your feature request related to a problem? Please describe.
Best practice is to have width
and height
attributes on images, so that the browser can reserve layout space prior to asset download, decode, and render. That's fine as long as all <source>
definitions deliver an image that's the same aspect ratio as the <img>
- you can just plop the width and height on the <img>
and call it done.
You need to do more when the sources are delivering differently cropped variants at different breakpoints - the width
and height
values on the img
may be "wrong" for the source
that is to be applied; resulting in the incorrect space being reserved for layout, and a resulting shift once the asset is loaded.
You'd want this sort of Picture behaviour when you're adapting an element in a design to do more than just scale objects at different breakpoints. e.g., shifting an image+text "card" so that the image is a thin strip running vertically on some views, but horizontally on others. etc.
source
when used in picture
supports both width
and height
properties to achieve mitigation of layout jank in these cases - Image Optimize doesn't seem to output this, or really offer a way to do this manually, from what I can see in the docs.
Describe the solution you would like
I want to be able to solve for art-directed transforms by being able to output markup along these lines:
<picture>
<!-- prefer webp, list these first. Order matters, first media to match is what's rendered - opposite of CSS rules -->
<source media="(max-width: 359px)" srcset="..." type="image/webp" width="370" height="370"><!-- square -->
<source media="(min-width: 680px)" srcset="..." type="image/webp" width="960" height="540"><!-- very landscape -->
<source media="(min-width: 360px)" srcset="..." type="image/webp" width="700" height="525"><!-- landscape -->
<!-- jpg fallbacks -->
<source media="(max-width: 359px)" srcset="..." type="image/jpeg" width="370" height="370">
<source media="(min-width: 680px)" srcset="..." type="image/jpeg" width="960" height="540">
<source media="(min-width: 360px)" srcset="..." type="image/jpeg" width="700" height="525">
<img
loading="lazy"
decoding="async"
src="..."
width="960"
height="540"
alt=""
>
</picture>
I've been able to do this with Imager / ImagerX but can't see how in Image Optimize.
Further, as I'm not 100% sure what browsers are doing in order to actually achieve this, I have in the past been using generated CSS to force this behaviour, by looping through the transformed assets to create CSS rules that will apply the correct aspect-ratio before the picture element is loaded - which again, I can't see how to accomplish with Image Optimizer:
<style>
/* We're in CSS now so order is opposite: last match is applied */
@media screen and (min-width: 360px) { #image-20-3689108 img { aspect-ratio: 1.3333333333333; } }
@media screen and (min-width: 680px) { #image-20-3689108 img { aspect-ratio: 1.7777777777778; } }
@media screen and (max-width: 359px) { #image-20-3689108 img { aspect-ratio: 1; } }
</style>
<picture id="image-20-3689108">
<!-- prefer webp, list these first. Order matters, first media to match is what's rendered - opposite of CSS rules -->
<source media="(max-width: 359px)" srcset="..." type="image/webp" width="370" height="370"><!-- square -->
<source media="(min-width: 680px)" srcset="..." type="image/webp" width="960" height="540"><!-- very landscape -->
<source media="(min-width: 360px)" srcset="..." type="image/webp" width="700" height="525"><!-- landscape -->
<!-- jpg fallbacks -->
<source media="(max-width: 359px)" srcset="..." type="image/jpeg" width="370" height="370">
<source media="(min-width: 680px)" srcset="..." type="image/jpeg" width="960" height="540">
<source media="(min-width: 360px)" srcset="..." type="image/jpeg" width="700" height="525">
<img
loading="lazy"
decoding="async"
src="..."
width="960"
height="540"
alt=""
/>
</picture>
This would be a great enhancement! You've made a clear description of the use case @MattWilcox. This will probably also help for lighthouse layout shift score? https://web.dev/cls/#layout-shift-score
So you can definitely this manually already with ImageOptimize, but I agree it'd be nice to have it done in a more automated way.