Содержание
Задача. На сайте могут добавляться скрипты (часто внешние), iframe
и другие элементы, которые добавляют на страницу различные элементы или функциональности, например: электронные читалки, аудиоплееры, виджет чата, видео-плеер и прочее. Как правило это влияет на скорость загрузки сайта и оценку в Pagespeed.web.dev, т.к. внешние скрипты подгружают свои элементы, шрифты и скрипты. В большинстве случаев нет необходимости загружать такие скрипты сразу при загрузке страницы. Достаточно отложить их загрузку и инициализировать только при каком-то событии. Например при клике на кнопку или движении мыши. Нет смысла сразу грузить виджет чата, ведь можно загрузить его когда пользователь явно уже начнет взаимодействовать с сайтом (двигать мышкой, скроллить, касаться экрана на мобильных).
Отложенная загрузка может очень хорошо прибаваить баллов в Pagespeed.
Отложенная загрузка скриптов по событию
Задача. На сайте могут добавляться скрипты, которые добавляют различные элементы на страницу, но нет необходимости в их загрузке сразу вместе со страницей. Например, в Код #1.1 показана читалка из ЛитРес и решение с подгрузкой по клику.
Важный момент, котрый нужно учесть здесь: первые три переменных нужно сделать глобальными window.litres_fragment_book_view_id
, а не просто оъявить через var
, иначе скрипт читалки, который загрузится в litres_fragment_body
, не найдет эти переменные, а в консоли будут сообщения вроде Uncaught ReferenceError: litres_widget_book_view_id is not defined.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<!-- Код читалки Литрес --> <div class="litres_fragment_body" style="width: 100%; height: auto;"></div> <script type="text/javascript"> var litres_fragment_book_view_id = 00000000;var litres_fragment_lfrom = 000000000;var litres_minheight = 500;(function(d, t){var lw = d.createElement(t),s = d.getElementsByTagName(t)[0];lw.async = 1;lw.src = "https://www.litres.ru/static/widgets/js/fragment.js";s.parentNode.insertBefore(lw, s);})(document, "script"); </script> <!-- Решение отложенной загрузки скрипта читалки Литрес --> <button id="load-litres">Загрузить</button> <div class="litres_fragment_body" style="width: 100%; height: auto;"></div> <script type="text/javascript"> var buttonReadBook= document.querySelector('#load-litres'); function loadLitresRead() { window.litres_fragment_book_view_id = 00000000; window.litres_fragment_lfrom = 000000000; window.litres_minheight = 500; var lw = document.createElement("script"),s = document.getElementsByTagName("script")[0]; lw.async = 1; lw.src = "https://www.litres.ru/static/widgets/js/fragment.js";s.parentNode.insertBefore(lw, s); } // Загрузить при клике на кнопку buttonReadBook.addEventListener('click', loadLitresRead); </script> |
Отложенная загрузка iframe
Задача. На странице могут выводиться iframe
видео, читалки, карты и прочее. Такие элементы можно загрузить позже, а не сразу.
Решение. Использование Intersection Observer API
[Код #2.1]. Добавим ссылку iframe
в атрибут data-src
. Если в браузере есть поддержка IntersectionObserver
, то загрузим ссылку из data-src
в src
, когда элемент станет видимым. Если поддержки нет, то загружаем ссылку при событиях движении мыши, скроллинге или касании экрана на смартфонах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<iframe class="iframe-lazy" data-src="https://www.youtube.com/embed/jzUTWUYBISM" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> <script> document.addEventListener("DOMContentLoaded", function() { var iframesLazy = document.querySelectorAll("iframe.iframe-lazy"); if ("IntersectionObserver" in window) { var iframeObserver = new IntersectionObserver(function (entries, observer) { entries.forEach(function (entry) { if (entry.isIntersecting && entry.target.src.length == 0) { entry.target.src = entry.target.dataset.src; iframeObserver.unobserve(entry.target); } }); }); iframesLazy.forEach(function (iframe) { iframeObserver.observe(iframe); }); } else { // Функция загрузки function loadiFrame() { if (iframesLazy) { for (let i = 0; i < iframesLazy.length; i++){ // Добавим в атрибут src значение из data-src if (iframesLazy[i].getAttribute('data-src')) { iframesLazy[i].setAttribute('src', iframesLazy[i].getAttribute('data-src')); } } // Снимаем обработчики событий после первого выполнения document.removeEventListener("mousemove", loadiFrame); document.removeEventListener("scroll", loadiFrame); document.removeEventListener("touchstart", loadiFrame); } } // Загрузить видео при движении мыши, скроле или касании на моб. document.addEventListener("mousemove", loadiFrame); document.addEventListener("scroll", loadiFrame); document.addEventListener("touchstart", loadiFrame); } }); </script> |
IntersectionObserver
— это API браузера, который позволяет отслеживать, когда целевой элемент становится видимым или перестает быть видимым в пределах контейнера (обычно это окно браузера или другой элемент). Он предоставляет эффективный способ отслеживать изменения в видимости элементов на странице.Если будет расчитано на подгрузку Ютуб-видео, то лучше обернуть и задать стили Код #2.2:
1 2 3 4 5 6 7 8 9 10 |
<div class="iframe-container"> <iframe class="iframe-lazy youtube" data-src="https://www.youtube.com/embed/jzUTWUYBISM" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> </div> <style> .iframe-container {position: relative; width: 100%; height: 0; padding-bottom: 56.25%;} .iframe-lazy.youtube {position: absolute; top: 0; left: 0; width: 100%; height: 100%;} </style> |
Загрузка Youtube-видео по событию
Задача. На сайте еразмещены Youtube-видео. Для лучшей производительности нам ненужно чтобы эти видео загружались сразу при загрузке страницы.
Решение. Подгрузку Youtube-видео можно решить несколькими общими способами, которые будут рассмотрены в этой статье. Но в этом разделе рассмотрим решение конкретно под Youtube. Чтобы отложить загрузку видео, можно вместо размещения самого кода вставлять какой-то html-элемент, где в специальном атрибуте указывать id Youtube-видео, а на сайт добавить JavaScript-код, который будет собирать эти элементы и при каком-то событии (клик, прокрутка, скроллинг) создавать iframe
самого видео с Youtube. [Код #3.1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<!-- Элементы с видео, в data-idYouVideo указан id Youtube-видео--> <div class="video-wrap" data-idYouVideo="hT0mmXYjJjw"></div> <div class="video-wrap" data-idYouVideo="5ihnSF-A9Qw"></div> <!-- <button class="load-video_btn"></div> --> <script> // Video Loading Script document.addEventListener("DOMContentLoaded", function() { // Получаем все элементы под видео с data-idYouVideo var videoContainer = document.querySelectorAll(".video-wrap"); /* // Кнопка загрузки видео если нужна var LoadVideoBtn = document.querySelector(".load-video_btn"); */ // Функция загрузки видео function loadVideo() { if (videoContainer.length > 0) { for (let i = 0; i < videoContainer.length; i++){ // Создадим в элементах iframe где в ссылку добавим id Ютуба let iframe = document.createElement("iframe"); iframe.src = "https://www.youtube.com/embed/" + videoContainer[i].getAttribute("data-idYouVideo"); iframe.loading = "lazy"; videoContainer[i].appendChild(iframe); } // Снимаем обработчики событий после первого выполнения document.removeEventListener("mousemove", loadVideo); document.removeEventListener("scroll", loadVideo); document.removeEventListener("touchstart", loadVideo); } } // Загрузить видео при движении мыши, скроле или касании на моб. document.addEventListener("mousemove", loadVideo); document.addEventListener("scroll", loadVideo); document.addEventListener("touchstart", loadVideo); /* document.addEventListener("click", loadVideo); LoadVideoBtn.addEventListener("click", loadVideo); // клик по кнопке */ }); </script> |
Отложенная загрузка видео по тегу <video>
Для видео, размещенное через тег <video>
простым решением для Lazy loading будет добавление атрибута – preload="none"
. Значение none
атрибута preload запрещает браузеру загружать видео и другие данные (например, мета-информацию о содержимом видео). Атрибут preload="none"
не будет работать, если в видео используется атрибут autoplay
(означает сразу начать загрузку).
Второй вариант ленивой загрузки видео — скрипт Код #4.1, который собирает все <video>
с классом lazy-video
, где вместо атрибута src
указан атрибут data-src
. Когда прокручивается страница до области видимости видео, скрипт заменяет data-src
на src
, и тогда браузер начинает загрузку данного видео.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
document.addEventListener("DOMContentLoaded", function() { var lazyLoadVideos = [].slice.call(document.querySelectorAll("video.lazy-video")); if ("IntersectionObserver" in window) { var lazyVideoObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(video) { if (video.isIntersecting) { for (var source in video.target.children) { var videoSource = video.target.children[source]; if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") { videoSource.src = videoSource.dataset.src; } } video.target.load(); video.target.classList.remove("lazy-video"); lazyVideoObserver.unobserve(video.target); } }); }); lazyLoadVideos.forEach(function(lazyVideo) { lazyVideoObserver.observe(lazyVideo); }); } }); |