Быстрые картинки на витрине - размеры, ленивая загрузка, WebP
Ускоряем витрину за счёт картинок: копии под место вывода, ленивая загрузка, набор размеров под экраны и современный формат изображения.
Что нужно знать заранее
Тяжёлые картинки - самая частая причина медленной витрины после запросов к базе. Одна фотография с фотоаппарата весит больше, чем весь остальной код страницы вместе с оформлением.
Платформа умеет делать уменьшенные копии и хранит их в своём каталоге. Копия создаётся при первом обращении, а дальше отдаётся веб-сервером напрямую, без участия кода страницы.
Ленивая загрузка помогает не всегда и при неверной настройке делает только хуже. Картинка первого экрана загружается сразу и без отсрочки, иначе посетитель видит пустое место вместо главного изображения.
Шаги
- Посчитать суммарный вес картинок на списке товаров и на детальной странице.
- Выводить уменьшенные копии, сделанные под фактический размер места вывода на странице.
- Отложить загрузку картинок ниже первого экрана и оставить верхние обычными.
- Добавить набор размеров, если картинка занимает разную ширину на экранах.
- Настроить отдачу современного формата и следить за размером каталога копий.
Решение
Считаем вес картинок страницы:
curl -s https://example.com/catalog/ | grep -oE 'src="[^"]+\.(jpg|png)"' | \ cut -d'"' -f2 | head -40 > /tmp/imgs.txtwc -l /tmp/imgs.txt # сколько картинок вообще на странице# дальше их вес смотрят панелью разработчика в браузере, вкладкой сетиСчитать надо не размер файла на диске, а вес того, что уходит посетителю. Список товаров с сорока картинками по два мегабайта грузится минуту даже при идеально быстром коде страницы.
Выводим копию под место вывода:
$img = CFile::ResizeImageGet($item['PREVIEW_PICTURE'], ['width' => 400, 'height' => 400], BX_RESIZE_IMAGE_PROPORTIONAL, true); // копия создаётся один раз, при первом показеecho '<img src="' . $img['src'] . '" width="400" height="400" alt="' . $item['NAME'] . '">';// ширина и высота в разметке убирают скачок вёрстки при загрузкеРазмер копии выбирают по фактическому месту в вёрстке, а не наугад. Копия под плитку каталога и копия под детальную страницу - это разные размеры, и делать одну на оба случая невыгодно.
Откладываем дальние картинки:
<img src="<?= $img['src'] ?>" loading="<?= $index < 4 ? 'eager' : 'lazy' ?>" width="400" height="400" alt="<?= $item['NAME'] ?>"><!-- первые карточки грузятся сразу: они на первом экране -->Ленивая загрузка ускоряет длинные списки и вредит первому экрану. Первые несколько карточек оставляют обычными, а остальные грузятся по мере прокрутки страницы посетителем.
Даём набор размеров под разные экраны:
$small = CFile::ResizeImageGet($id, ['width' => 400, 'height' => 400], BX_RESIZE_IMAGE_PROPORTIONAL, true);$large = CFile::ResizeImageGet($id, ['width' => 800, 'height' => 800], BX_RESIZE_IMAGE_PROPORTIONAL, true);echo '<img src="' . $small['src'] . '" srcset="' . $small['src'] . ' 400w, ' . $large['src'] . ' 800w"' . ' sizes="(max-width: 768px) 50vw, 400px" width="400" height="400" alt="">';Набор размеров нужен там, где картинка занимает разную ширину. Телефон получит лёгкий файл, а экран с высокой плотностью точек - крупный, и обе картинки будут выглядеть одинаково чётко.
Отдаём современный формат по заголовку запроса:
location ~* ^(/upload/.+)\.(jpe?g|png)$ { add_header Vary Accept; try_files $1.webp $uri =404; # файл нового формата отдаём только если он есть}# сами файлы готовят при загрузке картинки или отдельным заданием по каталогуСовременный формат весит заметно меньше при том же качестве. Файлы готовят заранее своим кодом или заданием по расписанию, а веб-сервер лишь выбирает, какой из двух файлов отдать посетителю.
Типичные проблемы
Список товаров грузится минуту на телефоне.
В плитку каталога выводятся оригиналы фотографий весом по несколько мегабайтов каждая. В список выводят уменьшенную копию, сделанную под фактический размер ячейки вёрстки.
Главная картинка появляется с задержкой.
Ленивая загрузка повешена на все картинки страницы подряд, включая изображения первого экрана. Изображения первого экрана грузят обычным способом, без отсрочки, чтобы главная картинка появилась сразу.
Каталог уменьшенных копий вырос до десятков гигабайтов.
Копии создаются под десятки разных размеров, приходящих из разных шаблонов сайта. Набор размеров сокращают, а каталог копий чистят при большой перегенерации.
Вёрстка прыгает при загрузке страницы.
У картинок не указаны ширина и высота прямо в разметке страницы. Браузер узнаёт размер только после загрузки файла и переставляет блоки.
Часть посетителей видит битые картинки.
Файл нового формата отдаётся всем подряд, включая браузеры без его поддержки. Формат выбирают по заголовку запроса и оставляют исходный файл на месте.
Частые вопросы
Где хранятся уменьшенные копии?
В отдельном каталоге загрузок, рядом с исходными файлами. Их не переносят при копировании сайта: они создаются заново при первом показе.
Нужно ли сжимать картинки до загрузки?
Да, исходники разумно уменьшать до нескольких тысяч точек по стороне. Копии делаются из оригинала, и гигантский исходник замедляет первую сборку страницы.
Сколько размеров копий держать?
Два-три на весь сайт: плитка, детальная страница и увеличенный просмотр. Каждый новый размер удваивает объём каталога копий и работу при перегенерации.
Помогает ли ленивая загрузка на детальной странице?
Да, для галереи дополнительных изображений и блоков ниже описания. Главную картинку товара при этом всегда грузят сразу.
Можно ли отдавать картинки через внешнюю сеть доставки?
Да, и для большого каталога это разумно. Настройка делается на стороне сервиса, а сайт продолжает отдавать те же адреса файлов.
Смежное
-
Медленный сайт - оглавление подтемы
-
Мобильная версия: адаптив, отдельный шаблон, кэш по устройству - что режут для телефонов
-
Сайт тормозит: разбор причин - с чего начинают разбор скорости
-
Картинки товара: загрузка, размеры и вывод галереи - работа с изображениями каталога
-
Тегированный кэш: сброс по изменению данных, а не по расписанию - кэш самой страницы
-
nginx и PHP-FPM: статика, пулы, медленные ответы - кто отдаёт файлы посетителю
-
Стили и скрипты в шаблоне: подключение, порядок, кэш - остальная статика страницы
-
Производительность сайта - раздел скорости целиком
-
Файлы платформы изнутри: таблица, каталоги, копии, удаление - откуда берутся уменьшенные копии
-
Кэш браузера и сжатие статики: заголовки, gzip, обновление - сколько картинка живёт в браузере