Closed adamsilverstein closed 2 years ago
One thing to consider can be the Blurhash algorithm:
Where the hash for the image can be stored as part of the meta of the image.
The Node.js AMP Optimizer has support for blurry image placeholders. Here's the implementation: https://github.com/ampproject/amp-toolbox/blob/main/packages/optimizer/lib/transformers/AddBlurryImagePlaceholders.js
The LQIP is quite a common pattern across the web now. I've worked on a few projects using https://github.com/aFarkas/lazysizes which also implements this paradigm.
One way of handling the low quality image, in order to save a server request is to encode it:
data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
This means that theres no request to the placeholder image and the browser can carry on its business without worrying about connectivity or download issues. Im sure that may increase the byte size of the final HTML resource, but if sites are using gzip
or brotli
I think this could be trivial.
I have implemented blurhash for the web stories plugin. I really liked it. I would be willing to work on this as a feature plugin.
I have implemented blurhash for the web stories plugin. I really liked it. I would be willing to work on this as a feature plugin.
That looks promising, can the blurhash approach use the base64 version of the placeholder mentioned above?
Did a bit of research on this @adamsilverstein - looks like its faster to run with blurhash
as opposed to implementing a base64
image - so maybe we just run with blurhash
?
Adding some additional ideas here in case we want to explore different alternatives:
One thing that we should remember is that images are indexed by search engines and one of the techniques to drive traffic to the site. If we replace images with placeholders, then this may cause images not being indexed by search engines and thus negatively affect the organic traffic for some sites.
JPEG has progressive compression that allows to achieve similar results: https://medium.com/hd-pro/jpeg-formats-progressive-vs-baseline-73b3938c2339#e3aa
Not sure how feasible it is to implement in our plugin.
JPEG has progressive compression that allows to achieve similar results: medium.com/hd-pro/jpeg-formats-progressive-vs-baseline-73b3938c2339#e3aa
Possibly we could take advantage of this with custom Image classes, we need to look into support in libgd and imagick. This wouldn't help with WebP images.
One thing that we should remember is that images are indexed by search engines and one of the techniques to drive traffic to the site. If we replace images with placeholders, then this may cause images not being indexed by search engines and thus negatively affect the organic traffic for some sites.
Good point that bears more investigation. Can the image(s) be listed in a meta tag to avoid that (ie og:image)?
My other concern about this change overall is how it might negatively impact the largest contentful paint measurement, how much of a hit will that take for this "perceived" performance boost, and is that acceptable?
I have looked at this a bit and a bit of code that works the approach I took was to add a background image to the img tag and removed the background on image load (for transparent images) I created the image using blurhash and stored the hash as image meta and then created the base64 on the render It might be better to store the base64 in DB to save having to recreate it each time but this would take more space I hacked some proof on concept code here https://github.com/pbearne/blurhash/blob/main/blurhash.php
onload="this.style.removeProperty('background');" style="background-size: cover; background-image: url(data:image/png;base64,iVBORw0KGgoAA......ORK5C=)
I need to add a filter to the media.php in core
$filtered_image = apply_filters( 'wp_img_tag_add_adjust', $filtered_image, $context, $attachment_id );
What I like about adding the image server-side is that don't have to wait for JS to render it but the downside is more data on the wire and isn't removed if no-JS (but we could handle that with CSS maybe)
Would this approach work?
I suspect that we will need a new filter for any approach we take to allow us to add elements to the img tags similar to this comint https://github.com/xwp/wordpress-develop/commit/2efb39b5a3942b475ebb0fa43c49dc6a92d243c9
@pbearne Very interesting, I was wondering about using the background - clever!
I need to add a filter to the media.php in core
Can you point specifically to where (or is there a ticket to add)? Could you try using wp_get_attachment_image
filter for now? That might be sufficient for the plugin.
Have you tested how this approach affects performance metrics?
JPEG has progressive compression that allows to achieve similar results: medium.com/hd-pro/jpeg-formats-progressive-vs-baseline-73b3938c2339#e3aa
@eugene-manuilov Good point, this is a great feature of jpegs.
When researching I found that LCP doesn't take progressive images into account currently (see https://github.com/w3c/largest-contentful-paint/issues/71) so I'm curious how any approach would affect both perceived and measured performance.
@adamsilverstein
Can you point specifically to where (or is there a ticket to add)? Could you try using
wp_get_attachment_image
filter for now? That might be sufficient for the plugin.
here is the filter I was looking at adding https://github.com/xwp/wordpress-develop/commit/2efb39b5a3942b475ebb0fa43c49dc6a92d243c9 I will look at the wp_get_attachment_image filter and see if I can use that instead
Have you tested how this approach affects performance metrics?
We are looking at the metrics it does add to the content on the wire so it may well be better to use JS to convert the blurhash into the background image
@adamsilverstein I have a working(ish) plugin https://github.com/pbearne/blurhash
@adamsilverstein I have a working(ish) plugin https://github.com/pbearne/blurhash
Was looking for this all over!
module for performance plugin https://github.com/xwp/performance/tree/INITS-199_domiant_color
interesting related ticket shared by Joy in slack: https://github.com/WICG/largest-contentful-paint/issues/68#issuecomment-742141525
@pbearne - https://github.com/WordPress/performance/pull/282 is a core patch right? Have you been able to implement this in the performance lab plugin (and if so, what is the PR for that)?
original conversation on slack
As low-res image you can use the preview contained in the exif data of the jpg, a method to get that image is to use the function exif-thumbnail (php exif module needed). To mention, it is possible for an image to not have a preview (not all have it, especially if they were stripped of metadata before being uploaded) so better to use it in combination with other methods.
this also allows us to color the drop shadow
box-shadow: var(--dominant-color) 0px 54px 55px;
or create a border
border: solid var(--dominant-color);
I have started writing the dev notes https://docs.google.com/document/d/1C7S-5GMw9R81fQOXrc2PjzEaQniMpIgg2dT1ta69LmQ/edit#heading=h.l8wdvygotok4
Thanks would be great to have permission to comment on the document to provide feedback, wanted to ask if we can include how the data (colors) are being stored in WordPress in order to inform plugins and external developers about this new property and how is stored in the database for later consumption.
Thanks @pbearne
@pbearne @spacedmonkey I've created a [Module] Dominant Color
label for the eventual module here.
Hey!
Stumbled upon this topic as I was researching why Google lighthouse did not like our implementation of lazy loading using https://imgproxy.net/
We got a response that might be interesting to this conversation as well so adding it here slightly redacted. This was in response to our questions about negative scoring due to doing a LQIP lazyloading solution using Imgproxy.
To quickly break it down: The core web vitals that are used for ranking, and appear in search console are the real user metrics that come from CrUX, so it's a reflection of what a user actually experienced.
The lighthouse powered lab test part (where recommendations for lazy-loading appear) aren't used for ranking, it's intended as a spot check to highlight best practices. Naturally an automated test can't always account for every use case, and sometimes the suggestions don't always match.
Lighthouse is open source, and you can raise an issue here: https://github.com/GoogleChrome/lighthouse/issues if you really feel the test is unfair.
However, I think in this case, you'd have a hard time convincing the team to support any kind of exception to the rules here, because I think your solution isn't without issues.
You appear to doing this low-quality > high-quality swap for the LCP element, makes it slower to actually achieve the rendering of the image, and destroys the browser preload scanning, therefore the ability to eagerly download the image and render.
I'd also argue that the pattern of instantly downloading a low quality image, then lazy-loading the higher quality version and swapping that in isn't a net gain, Ultimately you're loading more, the low quality image and the full res ones. That's really just an extra image load that's not benefiting anyone here.
Our Q: The placeholder solution gets around various cumulative layout issues because it keeps the width and height which lazy loading does not?
Thankfully all major browsers handle this for you, if you specify the native height and width, the browser calculates the aspect ratio and automatically reserves the space in layout, even if the image is resized with css to be responsive.
So I do think there are much more performant ways to do what you're trying to achieve, and you could leverage them and the excellent performance of the image proxy to make a great solution here.
Using the
<picture>
element (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) with
The new module from #282 in action - the comparison on an emulated slow connection nicely shows the UX enhancement from this module. Amazing work @pbearne @spacedmonkey!
https://user-images.githubusercontent.com/3531426/173693912-fae77670-a16b-4457-8e20-5a572786623f.mov
https://user-images.githubusercontent.com/3531426/173693941-eeb46d68-ed6d-4f73-a5ec-5b27f6e8e2ac.mov
Love it, great work ❤️
The LQIP approach, popularized by Medium, uses a very small placeholder image to enable a quicker initial page load. The idea is the placeholder gives the user a sense of the image shapes and color while consuming minimal bytes. The hires image then replaces the placeholder later in the page load cycle.
The approach may help with perceived performance, although in general more bytes will be consumed overall - the extra image, plus the JavaScript to make the placeholder work. This approach deserves more research and might remain plugin territory.
previously: https://github.com/adamsilverstein/modern-images-wp/issues/19