Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LazyImage] Webperfs and LCP considerations #1967

Merged
merged 1 commit into from
Jul 23, 2024

Conversation

Kocal
Copy link
Member

@Kocal Kocal commented Jul 7, 2024

Q A
Bug fix? no
New feature? no
Issues Fix #...
License MIT

Added some documentation to the LazyImage component, about LCP and webperfs considerations.

tl;dr: using the LazyImage in its initial way on the LCP image, will decrease your LCP, lower the user experience, and lower the ranking of your website on Google.

Using the style="background-image: url(...)" trick solves this issue, since it allows the browser to download and render the HD image the fastest as possible, while showing the blurhash during the loading.

This is something I've implemented ~1 month ago on our website wamiz.com, and did some comparaison:

  • Before, with the LazyImage Stimulus Controller solution, the blured image is not shown at all, and the LCP image discovered too much late: image
  • After, with the style="background-image: url(...)" trick, we can see the blured image and the LCP image discovered faster: image

@Kocal Kocal force-pushed the doc/lazy-image-webperfs branch 2 times, most recently from 83fdff3 to 437855d Compare July 7, 2024 07:08
@Kocal Kocal added the docs Improvements or additions to documentation label Jul 7, 2024
@Kocal Kocal requested review from kbond and smnandre July 7, 2024 07:09
@Kocal Kocal force-pushed the doc/lazy-image-webperfs branch 2 times, most recently from e9f15a8 to b4a659c Compare July 7, 2024 07:09
@seb-jean
Copy link
Contributor

seb-jean commented Jul 7, 2024

Good idea!
Will it also change with the srcset attribute? Is it a good idea to use the srcset attribute?

@Kocal
Copy link
Member Author

Kocal commented Jul 7, 2024

The attribute srcset won't be changed. With the new code added in the documentation, there is no <img> attribute manipulation during execution, the browser simply reads and executes src and style attributes.

But if you want to use srcset attributes, with preloading, I believe you can use something like this:

<img
    src="{{ preload(asset('image/large.png'), {
        as: 'image', 
        fetchpriority: 'high',
        imagesrcset: asset('image/large.png') ~ ' 1x, ' ~ asset('image/large2x.png') ~ ' 2x',
        imagesizes: '100vw'
    }) }}"
    srcset="{{ asset('image/large.png') }} 1x, {{ asset('image/large2x.png') }} 2x"
    sizes="100vw"

    style="background-image: url('{{ data_uri_thumbnail('public/image/large.png', 20, 15) }}')"
    fetchpriority="high"

    {# Using BlurHash, the size is required #}
    width="200"
    height="150"
/>

Is it a good idea to use the srcset attribute?

In the context of LazyImage and Blurhash image generation, nope, you can generate the Blurhash image with very very low dimensions:

  • here I've used 20x15 pixels for an original image of 200x150 pixels
  • on our app, I've used 10x5 pixels for original images of ~665x370 pixels, and it's really fine!

But more generally, yes, you don't want to load a 1200px wide image on a smartphone (~400/500px). You will prefer to load an image adapted to the device in order to reduce bandwidth consumption and increase download/display speed (especially true on mobiles with slow connections).

You can achieve that by using srcset attributes, or in a more naughty way, render an <img src="..."> depending on the user's device, and put your page in cache (by device type).

@smnandre
Copy link
Member

smnandre commented Jul 7, 2024

⚠️ very opiniated... opinion.

The follow message only concerns today and the future (a lot have changed since this package release).


I personally think this package/method in general should not be recommanded today.

First thing: the browsers are doing a much better job that any JS script will allow, so i'd recommand to use their optimisations.

loading=lazy with size/height attributes is de facto the most recommanded method to load images today.. and offer the best results in term of performances, accessibility, HTML weight, SEO..

If you have to wait more than 100ms for an image to load, you probably have other problems (an image over-sized, not in the best format, not compressed ...). First use srcset / picture sources attributes and you'll have done 99% of the job.

And if you absolutely (why?) need to display something in this tiny moment before the image is loaded, you can set some background svg, a gradient, a color..

To be complete, even the blurhash feels generally to me overkill (bringing itself some avoidable JS execution)


I'm very open to debate all this and ear your opinions :)

@seb-jean
Copy link
Contributor

seb-jean commented Jul 8, 2024

So for you, the following code is not recommended?

<img
    src="{{ asset('image/small.png') }}"
    srcset="{{ asset('image/small.png') }} 1x, {{ asset('image/small2x.png') }} 2x"

    {{ stimulus_controller('symfony/ux-lazy-image/lazy-image', {
        src: asset('image/large.png'),
        srcset: {
            '1x': asset('image/large.png'),
            '2x': asset('image/large2x.png')
        }
    }) }}
/>

@smnandre
Copy link
Member

smnandre commented Jul 8, 2024

I personnaly won't recommand it, today.

Main reason: why use a stimulus controller instead of loading lazy ?

Using native HTML provides better results in term of performance, accessibility, SEO...

@javiereguiluz
Copy link
Member

I agree with @smnandre. I think that the LazyImage UX package should be deprecated in favor of using the native HTML/browser features to lazy-load images.

@Kocal
Copy link
Member Author

Kocal commented Jul 13, 2024

Hi everyone, I think everyone here is right here, but also I think we don't speak about the same thing 😅

I didn't speak about image lazy-loading, which yes, should be done natively by the browser, without any JavaScript layer.

I'm speaking about the LCP image which should not be lazy-loaded, it should be loaded and displayed as soon as possible.
In this PR, I explain how we can hijack the initial Symfony UX BlurHash usage, to create a small placeholder image that is displayed when the real image is loaded, without any webperf costs.
The goal here is, thanks to this small placeholder image inlined in the HTML, to give the user a visual result instead of nothing.

@carsonbot carsonbot added Status: Reviewed Has been reviewed by a maintainer and removed Status: Needs Review Needs to be reviewed labels Jul 20, 2024
@javiereguiluz javiereguiluz merged commit e4a5897 into symfony:2.x Jul 23, 2024
2 checks passed
@javiereguiluz
Copy link
Member

Thanks Hugo! This contribution was finally merged.

While merging I did some very minor tweaks to the text, without changing any meaning: d649652

@Kocal Kocal deleted the doc/lazy-image-webperfs branch July 23, 2024 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Improvements or additions to documentation LazyImage Status: Reviewed Has been reviewed by a maintainer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants