alshedivat / al-folio

A beautiful, simple, clean, and responsive Jekyll theme for academics
https://alshedivat.github.io/al-folio/
MIT License
11.36k stars 11.28k forks source link

Webp images are not correctly being used and can result in long load times #1967

Closed bencbartlett closed 11 months ago

bencbartlett commented 12 months ago

Acknowledge the following

Describe the bug I have built a website using this template (which is wonderful by the way!) but the responsive images are not working the way I think they are intended to. Take a look at this page: https://bencbartlett.com/publications/. I have webp images for each publication thumbnail (example) but they are not correctly getting loaded by the browser and instead the full-size png images are loading. Try loading the linked publication page, open the inspection tools (cmd+opt+I) and go to the network tab and sort by waterfall plot, then do a hard refresh (cmd+shift+r) and you can see that none of the small webp images are loading. The viewports have a width of about 100px so the -150.webp images should load first.

With site.imagemagick enabled, in figure.html there is this snippet which I suspect is where the problem is but I have pretty limited web development experience so I'm not sure.

...
  <picture>
    {% if site.imagemagick.enabled %}
    {% for i in site.imagemagick.widths -%}
      <source
        class="responsive-img-srcset"
        media="(max-width: {{ i }}px)"     
        srcset="{{ img_path | relative_url }}-{{ i }}.webp"
      />
    {% endfor -%}
    {% endif %}

    <!-- Fallback to the original file -->
    ....
  </picture>

  {%- if include.caption -%}<figcaption class="caption">{{ include.caption }}</figcaption>{%- endif %}

</figure>

To Reproduce Steps to reproduce the behavior:

  1. Go to https://bencbartlett.com/publications/
  2. Open the inspection tools (cmd+opt+I) and go to the network tab and sort by waterfall plot, then do a hard refresh (cmd+shift+r)
  3. Observe that https://bencbartlett.com/assets/img/publication_preview/insitu_backprop-480.webp exists and should be a valid source tag.
  4. Look in the inspector and see that the small webp does not load first, and instead the full png which is several MB loads: https://bencbartlett.com/assets/img/publication_preview/insitu_backprop.png
  5. This drastically increases the loading time of the page and network footprint.

Expected behavior When you do the above, one of the small webp images should load instead of the png.

Screenshots If applicable, add screenshots to help explain your problem.

image

System (please complete the following information):

Additional context Add any other context about the problem here.

AndLen commented 11 months ago

This has been annoying me, too. I think it occurs when the max-width of the largest image is smaller than the viewport width, e.g. on higher-resolution laptop/desktop screens.

An "ugly" fix is to change the last element so it uses a min-width 1 pixel higher than the max-width of the second-to-last image. This guarantees that the largest element (i.e. webp image) will be used on a high-resolution display (rather than the fallback jpg/png).

For example, replacing the <source class="responsive-img-srcset" width="{{ i }}" media="(max-width: {{ i }}px)" srcset="{{ img_path | relative_url }}-{{ i }}.webp" > command with:

{% if forloop.last %}
    {% assign prev_index = forloop.index0 | minus: 1 %}
    {% assign prev_width = site.imagemagick.widths[prev_index] %}
    {% assign min_width = prev_width | plus: 1 %}
    <source class="responsive-img-srcset" width="{{ i }}" media="(min-width: {{ min_width }}px)" srcset="{{ img_path | relative_url }}-{{ i }}.webp" >
{% else %}
    <source class="responsive-img-srcset" width="{{ i }}" media="(max-width: {{ i }}px)" srcset="{{ img_path | relative_url }}-{{ i }}.webp" >
{% endif %}

There's probably a more elegant solution, so I haven't put this in a pull request! But it's a temporary fix...

george-gca commented 11 months ago

I don't think I understand both the problem and your solution @AndLen. Can you explain it a little more?

nWestie commented 11 months ago

This was confusing me too, think I figured it out though. The 'max-width' in the tag refers to the viewport width, not the rendered width of the image (The viewport width being the total pixel width of the website). So when the whole page is less then 1400px, it will use the 1400px resolution webp, when the whole screen is 800px, the 800px webp is used.

@AndLen's solution makes it so that the original is never used, rather whenever the viewport is larger than the width of the second largest webp, the largest is used.

It's unclear if there would be a way to what you(and I) want, which is to load an image based on the expected rendered size of an image, and do it automatically/fully contained in figure.html. I'm looking into it, but if someone with more experience knows that'd be great.