Коротко о том, что это и как реализуется:
Для примера рассмотрим вывод на странице простого изображения:
<img class="justImage" src="image.jpg">
Суть ленивой загрузки проста — изначально изображения на страницу выводятся с пустым атрибутом src, а путь прописывается в атрибуте data-src:
<img class="justImage" data-src="image.jpg">
В итоге загрузки картинки не происходит. Все, что остается сделать — это при появлении изображения в области видимости браузера (при прокрутке страницы, например) переместить данные из data-src в src, в результате чего картинка загрузится и отобразится.
В результате браузер при загрузке страницы не грузит сразу же все изображения, на ней присутствующие, а делает это по мере необходимости, то есть страница становится доступной гораздо быстрее. Как минимум, PageSpeed крайне положительно реагирует на это.
Это базовая реализация, можно вместо пустого src выводить размытую картинку с малым весом, или базовый цвет, или прелоадер и т.д.
Накидал на коленке плагин, упрощающий реализацию Lazy load для MODX Revolution. Он ищет img с классом lazy, забирает значение src, перекладывает его в data-src, подключает к странице скрипт yall.js (Yet Another Lazy Loader), исходники и описание скрипта тут: github.com/malchata/yall.js
Скрипт весит всего 2Кб, поэтому я его подключаю не отдельным файлом, а сразу в код страницы. Возможно, это не совсем правильно, если считаете, что правильнее по-другому — напишите в комментах, обсудим =)
То есть все, что требуется после установки плагина — это прописать класс lazy тем img, к которым нужно применить ленивую загрузку:
<img class="justImage lazy" src="image.jpg">
Плагин оформил в виде пакета дополнения MODX Revolution, вчера этот пакет появился в репозитарии MODX, так что можно просто установить пакет lazy load из репозитария и использовать функционал lazy load.
Либо можно добавить плагин вручную, дать ему любое имя и поставить галочку на событии OnWebPagePrerender:
<?php
if ($modx->event->name == 'OnWebPagePrerender') {
$content = &$modx->resource->_output;
preg_match_all('/]+>/i', $content, $images);
if (count($images)) {
foreach ($images[0] as $image) {
preg_match('/(class)=("[^"]*")/i', $image, $classValue);
$imageClasses = explode(" ", str_replace('"', '', $classValue[2]));
if (in_array("lazy", $imageClasses)) {
$img_real = str_replace(" src=", " data-src=", $image);
$content = str_replace($image, $img_real, $content);
}
}
}
}
Как обычно, код без бубна вставляться не хочет, поэтому здесь чуть модифицирую код по сравнению с тем, что в пакете репозитария.
Инлайн js код в этом модифицированном плагине отсутствует, поэтому нужно вручную в футере подключить скрипт github.com/malchata/yall.js/blob/master/dist/yall.min.js, предварительно скачав его и добавить строчку инициализации:
<sc ript src="путь_до_файла/yall.min.js"></sc ript>
<sc ript>document.addEventListener("DOMContentLoaded", yall);</sc ript>
Все равно криво добавляется, пробелы уберите в «sc ript»
Не уверен, что парсер местный еще что-то не съел, поэтому оставлю ссылку на статью, где корректный код выведен: Плагин Lazy load для MODX Revolution
Но, еще раз, плагин доступен в виде пакета lazy load, достаточно просто установить пакет и добавить класс lazy картинкам.
Робот 01.04.2019 10:31 #
Алексей Либер 02.04.2019 08:58 #
Единственное что я не понял: зачем делать таким образом?) Если в моем плагинчике идет проверка на браузер, генерация картинок и т.д., т.е. действия которые должна делать машина, то тут же можно изначально задавать ручками в тэге img атрибут data-src, а не просто src…
Собственно последние несколько лет так и делали всегда же) Или я что-то не понял?)
Олег 02.04.2019 09:22 #
Я делал ручками, да. Есть пара нюансов:
1. Ручками надо добавлять и класс и править src. Это чуть более напряжно, чем просто добавить класс. Когда чанк с одним вызовом картинки — да, без проблем. Но когда ВСЕ картинки в шаблоне прописаны вручную (волосы зашевелились когда это увидел, да) + раскиданы по шаблону (не подряд, когда легко и быстро ctrl-v, а ровным слоем размазаны по коду) + то же самое в нескольких чанках — уже заметно помогает. А мысль родить такой плагинчик возникла именно после работы с таким проектом. Ну и непосредственно роды начались, когда оказалось, что частично поломало верстку наличие лейзи картинок (не скажу, что зашевелилось, когда начал разбираться с версткой и скриптами) и нужно часть картинок вернуть в начальное состояние. И еще там же были блоки с background-image, прописаными инлайн. Их тоже лейзи делал, соответственно data-style в этих блоках. Как результат — слишком много сущностей, требующих внимания, очень захотелось упростить процесс.
2. Ручками — это надо понимать что ты делаешь и как надо сделать. Какой механизм работы lazyload, что менять, какой скрипт подключать (или самому колхозить). Тут все в одном, добавил плагин, заработало.
3. Да даже плагин не надо добавлять, поставил пакет из репозитария — все работает без OnWebPagePrerender и прочей магии.
4. Это бетка, в которой реализован основной функционал — работа с img, в планах потихоньку добавить все остальное, что умеет скрипт — picture, iframe, video и т.д.
Алексей Либер 02.04.2019 09:28 #
Я абсолютно ничего не имею против твоего решения, наоборот, просто вот этот финт ушами лично мне не понятен) А вот на счет проверки на класс — идея неплохая) Можно к себе опцию дописать)
Олег 02.04.2019 09:41 #
Без плагина надо:
1. Понимать, как работает lazy load, чтобы механизм реализовать вручную.
2. Подключить (предварительно поискав или навелосипедив) javascript, который будет реализовывать на фронте механизм этот.
3. Добавить класс lazy и дописать data- к каждому src.
Если делаешь это в каждом проекте — то рука набита, пункты 1, 2 уже реализованы.
Альтернативный вариант:
1. Установить дополнение lazy load
2. Добавить класс lazy к каждому src.
Без наработанного алгоритма — это намного быстрее.
То есть можем считать, что целевая аудитория — это начинающие разработчики, которые видя задачу «Нужна ленивая загрузка» начинают гуглить что это и как это, и на этом завершить дискуссию.
А можем дискуссию продолжить. Я бы всем картинкам сразу добавлял lazy, но иногда это ломает верстку. Есть мысли, как победить это? Добавлять вручную notLazy таким картинкам? =)
Алексей Либер 02.04.2019 09:59 #
Не уверен на счет поддержки селектора :not, но в крайнем случае можно в цикле проверить и исключить…
Олег 02.04.2019 10:09 #
А с php библиотеками — есть одна (как минимум) нехорошая штука. Что Simple HTML DOM Parser, что phpQuery — не совсем бережно с кодировкой обращаются. Как результат — либо костыли дикие прикручивать (во всяком случае, я простого решения не нашел), либо в сорцах страницы выводится поломанная кодировка, вся кириллица в виде абракадабр (именно в сорцах, на самом сайте в браузере — норм). Мне-то норм, отображается же в браузере, а сеошники очень громко ругались почему-то =)
P.S. Насчет Simple HTML DOM Parser — возможно, соврал. C кодировкой в DOMDocument была проблема точно. В Simple HTML DOM Parser — сейчас не скажу точно.
Алексей Либер 02.04.2019 10:21 #
А если серьезно и ты про то, что из-за отсутствующей картинки где-то что-то может съезжать, то можно делать следующее: брать размеры картинки, создавать пустое изображение с этим же размером и подсовывать его. Либо, чтобы не плодить пустышки — вообще в base64 отдавать.
Олег 02.04.2019 10:39 #
Шикарный вариант, но тут вопрос, кто кого раньше исключит =)
base64 — да ну, для больших картинок — не вариант. (блин, туплю с утра, ты про заглушку бесцветную, тогда как вариант пойдет)
С пустыми — норм. Только больше вариант с размытым изображением нравится, надо тестить, что там по размерам (в смысле веса) получится.
Алексей Либер 02.04.2019 10:58 #
Ilya Kozlov 24.04.2019 07:39 #
в файл стилей .css
/* Broken image symbol — скрываем браузерный символ, отсутсвующей картинки */
img.lazy:not([src]) {
visibility: hidden;
}
/* Lazy load images — плавное появление изображения */
img.lazy {
opacity: 1;
transition: opacity 25ms ease-in-out;
}
img.lazy[data-src] {
opacity: 0;
}
Ilya Kozlov 24.04.2019 10:53 #
img.lazy {
filter: blur(.5vw);
transform: scale(1.075);
}
img.lazy > .blur-in[data-src] {
will-change: transform, opacity;
animation: blur-in 1s ease-in-out;
}
@keyframes blur-in {
0% { transform: scale(1.075); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
Тимур 04.08.2019 19:41 #
Но дело в том, что у меня изображения выводятся еще и как srcset.
Например:
При добавлении класса lazy вид такой на фронте:
То есть src меняется на data-src, на srcset остается.
Я правильно понимаю что в данном случае ленивая загрузка не будет работать?