From b2de2275ae12bb920f0d6cf7cff92ec17aa226a5 Mon Sep 17 00:00:00 2001 From: Yurii Zusik Date: Mon, 22 Mar 2021 09:41:31 +0200 Subject: [PATCH] feat(storefront): BCTHEME-446 Improve performance of analyzing homepage carousel image --- .../carousel/utils/getActiveSlideInfo.js | 10 ++--- .../carousel/utils/handleImageAspectRatio.js | 36 ++++++++++-------- .../common/carousel/utils/handleImageLoad.js | 37 ++++++++++++++++--- assets/js/theme/common/utils/ie-helpers.js | 2 +- .../stencil/heroCarousel/_heroCarousel.scss | 9 +++++ 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js b/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js index c5b67c770e..3cdf46b7df 100644 --- a/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js +++ b/assets/js/theme/common/carousel/utils/getActiveSlideInfo.js @@ -5,16 +5,12 @@ export default ({ $slider }, isAnalyzedDataAttr) => { if (isAnalyzedSlide) return { isAnalyzedSlide }; const $activeSlideImg = $activeSlide.find('.heroCarousel-image'); - - const attrsObj = { - src: $activeSlideImg.attr('src'), - srcset: $activeSlideImg.attr('srcset'), - sizes: $activeSlideImg.attr('sizes'), - }; + const activeSlideImgNode = $activeSlideImg[0]; return { - attrsObj, $slider, $activeSlide, + $activeSlideImg, + activeSlideImgNode, }; }; diff --git a/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js b/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js index ef163e433e..ccd8ce6529 100644 --- a/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js +++ b/assets/js/theme/common/carousel/utils/handleImageAspectRatio.js @@ -6,7 +6,7 @@ const IMAGE_CLASSES = { }; const IS_ANALYZED_DATA_ATTR = 'image-ratio-analyzed'; -const defineClass = (imageAspectRatio) => { +const defineAspectRatioClass = (imageAspectRatio) => { switch (true) { case imageAspectRatio > 0.8 && imageAspectRatio <= 1.2: return IMAGE_CLASSES.square; @@ -17,13 +17,21 @@ const defineClass = (imageAspectRatio) => { } }; -export default ({ delegateTarget }, carousel) => { +const setAspectRatioClass = (imageNode, $slides) => { + if (imageNode.naturalHeight <= 1) return; + + const imageAspectRatio = imageNode.naturalHeight / imageNode.naturalWidth; + $slides.each((idx, slide) => $(slide).addClass(defineAspectRatioClass(imageAspectRatio))); +}; + +export default ({ delegateTarget }, carouselObj) => { const { isAnalyzedSlide, - attrsObj, $slider, $activeSlide, - } = getActiveSlideInfo(carousel || delegateTarget.slick, IS_ANALYZED_DATA_ATTR); + $activeSlideImg, + activeSlideImgNode, + } = getActiveSlideInfo(carouselObj || delegateTarget.slick, IS_ANALYZED_DATA_ATTR); if (isAnalyzedSlide) return; @@ -32,15 +40,13 @@ export default ({ delegateTarget }, carousel) => { if ($activeSlide.find('.heroCarousel-content').length) return; - $('') - .on('load', function getImageSizes() { - const imageHeight = this.height; - const imageWidth = this.width; - - if (imageHeight < 2 || imageWidth < 2) return; - - const imageAspectRatio = imageHeight / imageWidth; - $activeSlideAndClones.each((idx, slide) => $(slide).addClass(defineClass(imageAspectRatio))); - }) - .attr(attrsObj); + if (activeSlideImgNode.complete) { + if (activeSlideImgNode.naturalHeight === 1) { + /* if image is loaded but it still has not its own real height, + is image portrait or landscape will be analyzed next time when slide active */ + $activeSlideAndClones.each((idx, slide) => $(slide).data(IS_ANALYZED_DATA_ATTR, false)); + } else if (activeSlideImgNode.naturalHeight > 1) { + setAspectRatioClass(activeSlideImgNode, $activeSlideAndClones); + } + } else $activeSlideImg.on('load', () => setAspectRatioClass(activeSlideImgNode, $activeSlideAndClones)); }; diff --git a/assets/js/theme/common/carousel/utils/handleImageLoad.js b/assets/js/theme/common/carousel/utils/handleImageLoad.js index 66572db108..53aa1c734b 100644 --- a/assets/js/theme/common/carousel/utils/handleImageLoad.js +++ b/assets/js/theme/common/carousel/utils/handleImageLoad.js @@ -1,20 +1,45 @@ +import { isBrowserIE } from '../../utils/ie-helpers'; import getActiveSlideInfo from './getActiveSlideInfo'; const IMAGE_ERROR_CLASS = 'is-image-error'; const IS_ANALYZED_DATA_ATTR = 'image-load-analyzed'; -export default (e, carousel) => { +const generateImage = ($slide, $image) => { + $('') + .on('error', () => $slide.addClass(IMAGE_ERROR_CLASS)) + .attr({ + src: $image.attr('src'), + srcset: $image.attr('srcset'), + sizes: $image.attr('sizes'), + }); +}; + +export default (e, carouselObj) => { const { isAnalyzedSlide, - attrsObj, $activeSlide, - } = getActiveSlideInfo(carousel, IS_ANALYZED_DATA_ATTR); + $activeSlideImg, + activeSlideImgNode, + } = getActiveSlideInfo(carouselObj, IS_ANALYZED_DATA_ATTR); if (isAnalyzedSlide) return; $activeSlide.data(IS_ANALYZED_DATA_ATTR, true); - $('') - .on('error', () => $activeSlide.addClass(IMAGE_ERROR_CLASS)) - .attr(attrsObj); + if (activeSlideImgNode.complete) { + if (activeSlideImgNode.naturalHeight === 0) { + $activeSlide.addClass(IMAGE_ERROR_CLASS); + } else if (activeSlideImgNode.naturalHeight === 1) { + generateImage($activeSlide, $activeSlideImg); + } + + return; + } + + if (isBrowserIE) { + generateImage($activeSlide, $activeSlideImg); + return; + } + + $activeSlideImg.on('error', () => $activeSlide.addClass(IMAGE_ERROR_CLASS)); }; diff --git a/assets/js/theme/common/utils/ie-helpers.js b/assets/js/theme/common/utils/ie-helpers.js index c65b0c1275..8bfe9aa55d 100644 --- a/assets/js/theme/common/utils/ie-helpers.js +++ b/assets/js/theme/common/utils/ie-helpers.js @@ -1,3 +1,3 @@ -export const isBrowserIE = navigator.userAgent.includes('Trident'); +export const isBrowserIE = document.documentMode; export const convertIntoArray = collection => Array.prototype.slice.call(collection); diff --git a/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss b/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss index c109d870eb..10cff12547 100644 --- a/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss +++ b/assets/scss/components/stencil/heroCarousel/_heroCarousel.scss @@ -33,6 +33,15 @@ } } + // for IE + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + opacity: 0; + + &.slick-initialized { + opacity: 1; + } + } + &:not(.slick-initialized) :not(.heroCarousel-slide--first).heroCarousel-slide { display: none; }