[FIX] website: ensure lazy loaded images are loaded on zoomed Chrome

Before this commit, some images were never appearing on Chrome,
especially when using the 90% zoom.

Steps to reproduce (on a 1920x1080 screen and using Chrome):
1. Edit the homepage
2. Add a "Cover" block and setup a 50% min-height on it
3. Add 2 "Columns" blocks below the "Cover" block
4. Set the width of the first "Columns" snippet's first image to the
   recommended size (690px)
5. Save
6. As a public user, set the browser zoom to 90% and go to the page
   (you may need to reload the page again so images are in cache)

=> The first image of the second "Columns" block never appears.

opw-2731507

closes odoo/odoo#91075

X-original-commit: e9ef21b6cd5ae58322fa9102f9f34f06835f0485
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
qsm-odoo
2022-05-11 14:54:32 +02:00
parent 7dfd2e071e
commit b754a6f99d
@@ -13,6 +13,7 @@ const dom = require('web.dom');
var mixins = require('web.mixins');
var publicWidget = require('web.public.widget');
var utils = require('web.utils');
const wUtils = require('website.utils');
var qweb = core.qweb;
@@ -1353,6 +1354,73 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
},
});
/**
* The websites, by default, use image lazy loading via the loading="lazy"
* attribute on <img> elements. However, this does not work great on all
* browsers. This widget fixes the behaviors with as less code as possible.
*/
registry.ImagesLazyLoading = publicWidget.Widget.extend({
selector: '#wrapwrap',
/**
* @override
*/
start() {
// For each image on the page, force a 1px min-height so that Chrome
// understands the image exists on different zoom sizes of the browser.
// Indeed, without this, on a 90% zoom, some images were never loaded.
// Once the image has been loaded, the 1px min-height is removed.
// Note: another possible solution without JS would be this CSS rule:
// ```
// [loading="lazy"] {
// min-height: 1px;
// }
// ```
// This would solve the problem the same way with a CSS rule with a
// very small priority (any class setting a min-height would still have
// priority). However, the min-height would always be forced even once
// the image is loaded, which could mess with some layouts relying on
// the image intrinsic min-height.
const imgEls = this.$target[0].querySelectorAll('img[loading="lazy"]');
for (const imgEl of imgEls) {
// Write initial min-height on the dataset, so that it can also
// be properly restored on widget destroy.
imgEl.dataset.lazyLoadingInitialMinHeight = imgEl.style.minHeight;
imgEl.style.minHeight = '1px';
wUtils.onceAllImagesLoaded($(imgEl)).then(() => {
if (this.isDestroyed()) {
return;
}
this._restoreImage(imgEl);
});
}
return this._super(...arguments);
},
/**
* @override
*/
destroy() {
this._super(...arguments);
const imgEls = this.$target[0].querySelectorAll('img[data-lazy-loading-initial-min-height]');
for (const imgEl of imgEls) {
this._restoreImage(imgEl);
}
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @param {HTMLImageElement} imgEl
*/
_restoreImage(imgEl) {
imgEl.style.minHeight = imgEl.dataset.lazyLoadingInitialMinHeight;
delete imgEl.dataset.lazyLoadingInitialMinHeight;
},
});
return {
Widget: publicWidget.Widget,
Animation: Animation,