Lazy Loading изображений: настройка и ускорение сайта 2026

Lazy loading изображений — одна из тех вещей, которые я внедряю на каждом проекте без исключения. Казалось бы, простая техника, но на деле она способна поднять PageSpeed с 40 до 85+ и реально сократить время первой загрузки страницы в 2-3 раза.

Что такое lazy loading и почему это важно в 2026

Грубо говоря, lazy loading — это отложенная загрузка изображений. Браузер не тащит все картинки сразу при открытии страницы, а подгружает их только тогда, когда пользователь прокручивает страницу до нужного места. Звучит банально, но эффект на практике — колоссальный.

У меня был клиент с интернет-магазином на Битриксе: каталог с 200+ товарами на странице, каждый с несколькими изображениями. Страница весила около 18 МБ только картинками. PageSpeed Insights давал 23 балла на мобильных. После внедрения lazy loading и базовой оптимизации — 78 баллов. Без изменения хостинга, без переписывания кода, просто правильная настройка загрузки изображений.

В 2026 году это особенно критично. Google уже несколько лет учитывает Core Web Vitals в ранжировании, и показатель LCP (Largest Contentful Paint) напрямую зависит от того, как грузятся изображения. Если у вас "простыня" с картинками, которые все загружаются разом — вы буквально дарите позиции конкурентам. Про это я подробно писал в статье Core Web Vitals: как улучшить показатели — там много связанных техник.

Ещё один момент: мобильный трафик. По моей статистике с проектов, 60-75% посетителей заходят с телефонов. Мобильный интернет — это не всегда 5G в Москве. Это порой 3G в Подмосковье или вообще EDGE в регионах. Каждый лишний мегабайт изображений — это секунды ожидания и потерянные конверсии.

Нативный lazy loading: атрибут loading="lazy"

Начну с самого простого. С 2019 года все современные браузеры поддерживают нативный lazy loading через атрибут loading="lazy". Это буквально одно слово в HTML-коде, которое уже решает 80% задач.

<!-- Обычная картинка без lazy loading -->
<img src="product-photo.jpg" alt="Фото товара" width="800" height="600">

<!-- С нативным lazy loading -->
<img src="product-photo.jpg" alt="Фото товара" width="800" height="600" loading="lazy">

<!-- Для первого изображения на странице (выше fold) — НЕ ставим lazy! -->
<img src="hero-banner.jpg" alt="Главный баннер" width="1920" height="600" loading="eager" fetchpriority="high">

Важный нюанс, который многие упускают: атрибут loading="lazy" нельзя вешать на все изображения подряд. Главный баннер, логотип, первое изображение товара — всё, что видно без прокрутки (above the fold) — должно грузиться с loading="eager" или вообще без этого атрибута. Если поставить lazy на hero-изображение, LCP улетит в минус, и PageSpeed накажет вас.

Поддержка браузерами в 2026 году — практически 97%+. Забудьте про IE11 (его уже нет в живых), а все актуальные Chrome, Firefox, Safari, Edge поддерживают нативный lazy loading отлично. Так что полифиллы для большинства проектов уже не нужны.

⚠️
Критическая ошибка: Никогда не добавляйте loading="lazy" к изображениям в первом экране (hero, логотип, первый продукт). Это гарантированно ухудшит LCP и снизит оценку PageSpeed. Правило простое: lazy только для картинок ниже условной линии "первого экрана".

Lazy loading в WordPress: плагины и ручная настройка

WordPress начиная с версии 5.5 автоматически добавляет loading="lazy" ко всем изображениям через функцию wp_lazy_loading_enabled. Но, честно говоря, стандартная реализация — это минимум. На деле нужно доработать.

Первое, что я всегда делаю на WordPress-проектах — это проверяю, что первое изображение на странице получает fetchpriority="high". В WordPress 6.3+ это добавляется автоматически для LCP-изображения, но не всегда корректно определяется. Проверяю через DevTools → Performance → LCP element.

<?php
// functions.php — убираем lazy loading с первого изображения в посте
add_filter( 'wp_lazy_loading_enabled', function( $default, $tag_name, $context ) {
    // Отключаем lazy для featured image в single post
    if ( $tag_name === 'img' && $context === 'the_post_thumbnail' && is_single() ) {
        return false;
    }
    return $default;
}, 10, 3 );

// Добавляем fetchpriority="high" к featured image
add_filter( 'wp_get_attachment_image_attributes', function( $attr, $attachment, $size ) {
    // Только для главного изображения поста
    if ( is_single() && $attachment->ID === get_post_thumbnail_id() ) {
        $attr['fetchpriority'] = 'high';
        unset( $attr['loading'] ); // убираем lazy
    }
    return $attr;
}, 10, 3 );
?>

Из плагинов я обычно рекомендую Smush (версия 3.x) или ShortPixel — они умеют не только lazy loading, но и конвертацию в WebP, что в связке даёт отличный результат. Про WebP я отдельно написал статью Настройка WebP и оптимизация изображений на сайте в 2026 — там подробно про конвертацию и настройку.

Ещё один вариант — плагин Flying Images. Небольшой, без раздутого функционала, делает именно то, что нужно: агрессивный lazy loading с intersection observer. На одном проекте с ним я получил прирост PageSpeed на мобильных с 51 до 79 баллов.

Lazy loading в Битриксе: настройка без потери функционала

В Битриксе ситуация интереснее. Стандартный компонент catalog.section, например, выводит изображения без какого-либо lazy loading. Нужно либо дорабатывать шаблоны, либо использовать JavaScript-решение.

Я обычно иду через кастомизацию шаблонов компонентов. В Битриксе каждый шаблон — это PHP-файл, который можно редактировать. Открываю template.php нужного компонента и меняю вывод изображений:

<?php
// В шаблоне компонента catalog.section/template.php
// Было:
?>
<img src="<?=$arItem['PREVIEW_PICTURE']['SRC']?>" 
     alt="<?=$arItem['NAME']?>">

<?php
// Стало — с нативным lazy loading и размерами:
?>
<img 
    src="<?=$arItem['PREVIEW_PICTURE']['SRC']?>"
    alt="<?=$arItem['NAME']?>"
    width="<?=$arItem['PREVIEW_PICTURE']['WIDTH']?>"
    height="<?=$arItem['PREVIEW_PICTURE']['HEIGHT']?>"
    loading="lazy"
    decoding="async"
>

Атрибут decoding="async" — это отдельная маленькая оптимизация. Он говорит браузеру декодировать изображение асинхронно, не блокируя основной поток. В связке с lazy loading работает отлично.

Но есть нюанс с Битриксом: если используется компонент bitrix:main.file.input или встроенный редактор, изображения могут вставляться без атрибутов. Решается через глобальный JavaScript-хук, который добавляет loading="lazy" ко всем изображениям после загрузки DOM, кроме первого видимого.

Про кеширование в Битриксе, кстати, отдельная история — там есть свои тонкости. Если не настроен кеш, lazy loading помогает меньше, потому что сервер всё равно генерирует HTML со всеми тегами img. Подробно про это в статье Настройка кеширования в Битрикс: полное руководство.

JavaScript Intersection Observer: когда нативного недостаточно

Нативный lazy loading хорош, но у него есть ограничения. Он не работает с фоновыми изображениями CSS, не даёт контроля над threshold (расстоянием предзагрузки), и не поддерживает кастомные эффекты появления. Для этих случаев я использую Intersection Observer API.

// Современный lazy loading через Intersection Observer
// Работает с img[data-src] и элементами с data-bg

document.addEventListener('DOMContentLoaded', function() {
    
    // Настройки: rootMargin — предзагружаем за 300px до появления
    const lazyLoadOptions = {
        rootMargin: '300px 0px',
        threshold: 0.01
    };

    const lazyLoadObserver = new IntersectionObserver(function(entries, observer) {
        entries.forEach(function(entry) {
            if (entry.isIntersecting) {
                const element = entry.target;
                
                // Для тега img
                if (element.tagName === 'IMG') {
                    if (element.dataset.src) {
                        element.src = element.dataset.src;
                    }
                    if (element.dataset.srcset) {
                        element.srcset = element.dataset.srcset;
                    }
                    element.classList.add('loaded');
                }
                
                // Для фоновых изображений
                if (element.dataset.bg) {
                    element.style.backgroundImage = `url(${element.dataset.bg})`;
                    element.classList.add('loaded');
                }
                
                observer.unobserve(element);
            }
        });
    }, lazyLoadOptions);

    // Наблюдаем за всеми элементами с data-src или data-bg
    document.querySelectorAll('img[data-src], [data-bg]').forEach(function(el) {
        lazyLoadObserver.observe(el);
    });
});

// CSS для плавного появления
// .lazy-img { opacity: 0; transition: opacity 0.3s; }
// .lazy-img.loaded { opacity: 1; }

Это решение я использую когда нужен эффект fade-in при появлении картинок, или когда работаю с фоновыми изображениями секций. Например, на лендингах с параллакс-эффектом — там фоны через CSS background-image, нативный lazy loading не поможет, только JS.

Параметр rootMargin: '300px 0px' — это отступ от края viewport. Браузер начинает загружать изображение за 300px до того, как оно появится в экране. На быстром интернете можно поставить 100px, на медленном лучше 500px. Я обычно ставлю 300px как золотую середину.

💡
Совет из практики: Не используйте сторонние библиотеки типа lazysizes или lozad.js для новых проектов. В 2026 году нативный loading="lazy" + Intersection Observer для фонов покрывают 99% задач. Меньше зависимостей — быстрее сайт. Каждый лишний JS-файл — это запрос к серверу и время парсинга.

Nginx и серверная оптимизация в связке с lazy loading

Lazy loading — это клиентская оптимизация, но она работает в разы лучше, если сервер настроен правильно. Вот что я обязательно проверяю на сервере при внедрении lazy loading.

Первое — кеширование изображений в браузере. Если картинки не кешируются, при каждом скролле и повторном визите они будут загружаться заново. Настройка в Nginx:

server {
    # Кеширование статических файлов
    location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|avif)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
        
        # Отдаём WebP если браузер поддерживает
        add_header Vary "Accept";
    }
    
    # Сжатие для SVG (остальные форматы уже сжаты)
    gzip on;
    gzip_types image/svg+xml;
    
    # HTTP/2 для параллельной загрузки
    listen 443 ssl http2;
    
    # Предзагрузка критических изображений через Link header
    location = / {
        add_header Link "</images/hero.webp>; rel=preload; as=image; type=image/webp";
    }
}

Обратите внимание на заголовок Link с rel=preload — это серверный preload для hero-изображения. В связке с lazy loading для остальных картинок это идеальная стратегия: главное изображение предзагружается максимально быстро, остальные — по мере необходимости.

Второе — HTTP/2. Без него браузер ограничен 6 параллельными соединениями к одному домену. С HTTP/2 — мультиплексирование, можно грузить десятки ресурсов параллельно. Про настройку HTTP/2 и HTTP/3 я писал отдельно в Настройка HTTP/2 и HTTP/3 для ускорения сайта в 2026 — там всё подробно.

Третье — CDN. Если изображения раздаются с CDN, они физически ближе к пользователю, и lazy loading работает ещё эффективнее — картинки подгружаются быстрее, пользователь не замечает задержки при скролле.

Lazy loading и SEO: как не навредить индексации

Честно говоря, это тема, которую многие недооценивают. Googlebot в 2026 году отлично рендерит JavaScript и видит изображения, загруженные через Intersection Observer. Но есть нюансы.

Если вы используете data-src вместо src для JS-решения, убедитесь, что у изображений есть правильный alt. Googlebot индексирует alt-тексты даже до рендеринга JS. А вот если alt пустой или отсутствует — это потеря для SEO, независимо от lazy loading.

Нативный loading="lazy" с обычным src — абсолютно безопасен для SEO. Googlebot загружает изображения нормально, потому что при краулинге он не "прокручивает" страницу — он просто запрашивает URL изображения из атрибута src.

Яндекс.Бот ведёт себя чуть иначе — он хуже рендерит JavaScript, чем Googlebot. Поэтому для SEO я всегда рекомендую нативный lazy loading как основу. JS-решение только для фонов и дополнительных эффектов.

ℹ️
SEO и lazy loading: Всегда используйте настоящий атрибут src в теге img — даже если добавляете loading="lazy". Никогда не заменяйте src на data-src для основных SEO-важных изображений (товары, статьи). Это нужно только для JS-fallback или фоновых изображений.

Измерение результатов: что и как проверять

После внедрения lazy loading я всегда провожу замеры через несколько инструментов. Один PageSpeed Insights — недостаточно. Вот мой стандартный чеклист проверки.

Google PageSpeed Insights — смотрю на показатели LCP, TBT, Speed Index. После правильного внедрения lazy loading LCP должен улучшиться, потому что браузер не тратит пропускную способность на загрузку невидимых картинок. Реальные цифры с моих проектов: LCP снижался с 4.2s до 1.8s на мобильных.

Chrome DevTools → Network — включаю throttling на "Fast 3G" и смотрю waterfall. Должно быть видно, что изображения ниже fold не загружаются при первом открытии страницы. Если вижу, что все картинки грузятся сразу — значит lazy loading не работает.

Lighthouse в режиме аудита — там есть отдельная проверка "Defer offscreen images". Если после настройки эта рекомендация исчезает — всё сделано правильно. Про полный аудит через Lighthouse писал в Lighthouse 2026: аудит и улучшение скорости сайта.

Конкретный кейс: проект на Laravel + Vue.js, галерея портфолио с 80 изображениями. До: LCP 5.1s, PageSpeed mobile 31. После lazy loading + WebP + правильные размеры: LCP 1.4s, PageSpeed mobile 84. Клиент был доволен — позиции в Яндексе выросли в течение 3 недель после изменений.

Частые ошибки при настройке lazy loading

За годы практики я насмотрелся на самые разные реализации. Вот ошибки, которые встречаю чаще всего.

Lazy loading на всех изображениях подряд. Это плохая идея — уже объяснял выше. Первый экран должен загружаться без задержек. Встречал сайты, где lazy стоял на логотипе в шапке — логотип просто не отображался первые секунды. Это не только PageSpeed, это просто плохой UX.

Отсутствие атрибутов width и height. Без явных размеров браузер не знает, сколько места зарезервировать под картинку. Результат — Cumulative Layout Shift (CLS): контент прыгает при загрузке. CLS — один из Core Web Vitals, Google за него наказывает. Всегда указывайте width и height, даже если используете CSS для адаптивности.

Слишком маленький rootMargin в JS-реализации. Если картинка начинает загружаться только когда уже видна — пользователь видит пустое место или placeholder. Нужно начинать загрузку заблаговременно. Мой стандарт — 300-500px до viewport.

Игнорирование placeholder. Пока картинка не загрузилась, что показывать? Пустое место — плохо. Лучшие варианты: размытая миниатюра (LQIP — Low Quality Image Placeholder), однотонный фон цвета картинки, или SVG-заглушка. Я обычно использую LQIP — это небольшое base64-изображение прямо в HTML, оно загружается мгновенно и создаёт плавный эффект перехода.

Lazy loading в письмах. Встречал разработчиков, которые добавляли loading="lazy" к изображениям в HTML-письмах. Это бессмысленно — почтовые клиенты этот атрибут игнорируют. Но хуже не делает, просто лишний код.

Если после внедрения lazy loading что-то пошло не так — сайт ведёт себя странно, изображения не грузятся — загляните в статью Как исправить ошибки на сайте: чек-лист, там есть методичный подход к диагностике.

Что нового в lazy loading в 2026: современные подходы

Технологии не стоят на месте. В 2026 году появились интересные дополнения к базовому lazy loading.

Priority Hints (fetchpriority). Атрибут fetchpriority="high|low|auto" теперь поддерживается во всех актуальных браузерах. Он позволяет явно указать приоритет загрузки. Hero-изображение — fetchpriority="high". Изображения в футере — fetchpriority="low". В связке с lazy loading это даёт тонкий контроль над порядком загрузки.

AVIF как альтернатива WebP. Формат AVIF даёт ещё лучшее сжатие, чем WebP — в среднем на 30-50% меньше. Поддержка браузерами уже 93%+. Я начал использовать AVIF с fallback на WebP на новых проектах. В Nginx это настраивается через $http_accept — аналогично WebP, просто добавляется ещё один уровень приоритета.

Speculation Rules API. Новый браузерный API позволяет предзагружать страницы при наведении на ссылку. Не совсем lazy loading, но из той же области — управление загрузкой ресурсов. На сайтах с высоким трафиком это ощутимо улучшает perceived performance.

По опыту скажу: самая мощная комбинация в 2026 году — это нативный loading="lazy" + AVIF/WebP форматы + правильные размеры с srcset + HTTP/2 на сервере. Каждый элемент усиливает другой. Если нужна помощь с настройкой всего этого комплекса — обращайтесь на доработку сайта, настрою правильно и с замерами до/после.

Если работаете на WordPress — отдельная услуга поддержки WordPress включает аудит производительности и внедрение всех современных оптимизаций. Для Битрикс — аналогично через поддержку Битрикс.

Главный вывод после всего этого опыта: lazy loading — не серебряная пуля, но это обязательный базовый слой оптимизации. Без него всё остальное работает вполсилы. Внедряйте, замеряйте, итерируйте. Разница в PageSpeed и, главное, в реальном поведении пользователей — ощутимая.

Хотите ускорить загрузку вашего сайта прямо сейчас?

Наши специалисты настроят Lazy Loading и оптимизируют производительность вашего сайта под современные стандарты 2026 года.

П
Павел
Веб-разработчик · 10+ лет опыта · Bitrix, WordPress, Laravel

Читайте также

Защита XML-RPC и wp-login.php: полное руководство 2026 Настройка SSH-ключей для сервера: безопасный доступ 2026 Как выбрать хостинг для сайта: на что обратить внимание