Lazy load media

Seo 2 хвилин 45 секунд 17 вер. 2022
 Lazy load media

На сьогодні сайти дуже переповнені різного роду контентом як відео, так і зображеними. Постає питання як це все вірно показувати. 
В більшості випадків ніхто не задумується над цим, але коли постає питання швидкості завантаження сторінки, де кожна секунда важлива, кидають погляд в сторону відкладеного завантаження контенту.

Логіка така - навіщо показувати картинки чи відео під час завантаження сторінки (якщо цього не потрібно), до моменту коли це реально потрібно.

Наприклад картинки внизу сайту нам не потрібно завантажувати разом зі всією сторінкою, до моменту поки користувач не бачить місце це вона має бути. 

Реалізуємо невеликий js скрипт, що буде завантажувати картинки не разом зі сторінкою, а після.
Для цього замінимо

<img src="/image.jpg" />

на

<img data-src="/image.jpg" />

Та приєднаємо скрипт. Все просто, знаходимо всі картинки і якщо data-src беремо url та вставляємо в src

document.querySelectorAll('img').forEach(item=>{
	
			if (item.dataset.src){
			   item.src = item.dataset.src
				item.removeAttribute('data-src')

			}		
		
	})

Аналогічно можливо зробити для video, iframe.

Але це сильно просто і не дуже ефективно. Реалізуймо підвантаження коли елемент попадає в зону видимості скриптом, якому потрібно передати елемент, що шукаємо.

 function isInViewport(el) {
        const rect = el.getBoundingClientRect();
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.outerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)

        );
    }

Тепер зберемо все разом, і реалізуємо активацію при пролистуванні

Кінцевий варіант для картинок відео та iframe буде виглядати так.

(function (){
    /**
     * isInViewport
     * @param el
     * @returns {boolean}
     */
    function isInViewport(el) {
        const rect = el.getBoundingClientRect();
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.outerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)

        );
    }

    document.addEventListener('scroll', LLoad, {
        passive: true
    });

    /**
     *
     * @constructor
     */
    function LLoad() {

        document.querySelectorAll('video,source,iframe').forEach(item => {

            if (item.dataset.src && isInViewport(item)) {
                item.src = item.dataset.src
                item.removeAttribute('data-src')

            }

        })
    }
    LLoad()
})()

Приклад на Сodepen

Та бувають випадки коли контент встановлений як фон блоку. Тому так само можемо замінити контент фону. Перед цим додавши url контенту в дата параметр типу data-bg та додавши клас lazy-bg

<div data-bg="/image.jpg" class="lazy-bg"></div>

Додамо зміни в скрипт:

(function (){
    /**
     * isInViewport
     * @param el
     * @returns {boolean}
     */
    function isInViewport(el) {
        const rect = el.getBoundingClientRect();
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.outerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)

        );
    }

    document.addEventListener('scroll', LLoad, {
        passive: true
    });

    /**
     *
     * @constructor
     */
    function LLoad() {

        document.querySelectorAll('img,video,source,iframe,.lazy-bg').forEach(item => {

            if (item.dataset.src && isInViewport(item)) {
                item.src = item.dataset.src
                item.removeAttribute('data-src')

            }
            /**
             * Replace bg
             */
            if (item.dataset.bg && isInViewport(item)){
                let src = item.dataset.bg
                item.style.background = `url("${src}")`;
                item.style.backgroundPosition = 'center center';
                item.style.backgroundSize = 'cover';

            }

        })
    }
    LLoad()
})()