Lazy loading библиотеки

Lazy loading — техника, позволяющая загружать и рендерить элементы страницы только по мере необходимости, снижая нагрузку на браузер и ускоряя отображение контента. В контексте Masonry это особенно важно, так как сетка может содержать десятки и сотни элементов, и одновременная их отрисовка может привести к падению производительности.

Подключение Masonry с поддержкой ленивой загрузки

Для корректной работы lazy loading в Masonry важно правильно инициализировать библиотеку и убедиться, что элементы добавляются динамически после загрузки:

import Masonry from 'masonry-layout';
import imagesLoaded from 'imagesloaded';

const grid = document.querySelector('.grid');

const msnry = new Masonry(grid, {
  itemSelector: '.grid-item',
  columnWidth: '.grid-sizer',
  percentPosition: true
});

// Обеспечение правильного отображения изображений
imagesLoaded(grid).on('progress', function() {
  msnry.layout();
});

Здесь ключевое значение имеет imagesLoaded, которое гарантирует, что Masonry пересчитает позиции элементов только после полной загрузки всех изображений.

Реализация ленивой загрузки изображений

Lazy loading изображений может быть выполнен через атрибут loading="lazy" в HTML:

<div class="grid-item">
  <img src="image1.jpg" loading="lazy" alt="Описание">
</div>

Однако для динамически подгружаемых элементов потребуется дополнительная логика на JavaScript. Например, используя Intersection Observer:

const lazyImages = document.querySelectorAll('img[loading="lazy"]');

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.addEventListener('load', () => {
        msnry.layout();
      });
      observer.unobserve(img);
    }
  });
}, { rootMargin: '200px' });

lazyImages.forEach(img => observer.observe(img));

Ключевые моменты:

  • dataset.src хранит реальный путь изображения.
  • После загрузки изображения вызывается msnry.layout() для корректной перестройки сетки.
  • rootMargin позволяет подгружать элементы заранее, когда они почти видны пользователю.

Динамическая подгрузка элементов (Infinite scroll)

Для интеграции Masonry с бесконечной прокруткой необходимо добавлять новые элементы в DOM и сразу обновлять сетку:

function appendItems(itemsHTML) {
  const tempDiv = document.createElement('div');
  tempDiv.innerHTML = itemsHTML;
  const items = tempDiv.querySelectorAll('.grid-item');
  grid.append(...items);

  imagesLoaded(items).on('progress', function() {
    msnry.appended(items);
  });
}

Здесь msnry.appended(items) сообщает Masonry о появлении новых элементов и пересчитывает их расположение.

Оптимизация производительности

  1. Фрагментация загрузки: добавлять элементы партиями по 10–20 штук, чтобы избежать долгой блокировки основного потока.
  2. Debounce при прокрутке: если подгрузка элементов привязана к scroll-событию, использовать debounce или throttle для предотвращения частых вызовов.
  3. Минимизация пересчетов layout: вызывать msnry.layout() только после загрузки группы изображений, а не каждого элемента отдельно.

Совместимость с другими библиотеками

Lazy loading Masonry легко интегрируется с:

  • Infinite Scroll — автоматическая подгрузка новых блоков по мере прокрутки.
  • Lightbox — корректное отображение модальных окон после динамической подгрузки.
  • React/Vue — через refs или mounted хуки можно инициализировать Masonry после рендеринга элементов.

Особенности работы с изображениями разных размеров

Для сеток с контентом переменной высоты важно:

  • Использовать imagesLoaded для каждого нового блока.
  • Выбирать стратегию column width: фиксированная колонка (columnWidth) или процентная ширина (percentPosition).
  • Добавлять placeholder-изображения или минимальные размеры контейнеров, чтобы Masonry не «прыгал» при загрузке контента.

Итоговая структура кода для lazy loading

const grid = document.querySelector('.grid');

const msnry = new Masonry(grid, {
  itemSelector: '.grid-item',
  columnWidth: '.grid-sizer',
  percentPosition: true
});

const lazyImages = document.querySelectorAll('img[loading="lazy"]');

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.addEventListener('load', () => msnry.layout());
      observer.unobserve(img);
    }
  });
}, { rootMargin: '200px' });

lazyImages.forEach(img => observer.observe(img));

function appendItems(itemsHTML) {
  const tempDiv = document.createElement('div');
  tempDiv.innerHTML = itemsHTML;
  const items = tempDiv.querySelectorAll('.grid-item');
  grid.append(...items);

  imagesLoaded(items).on('progress', () => msnry.appended(items));
}

Такой подход обеспечивает плавное добавление контента, минимизирует нагрузку на браузер и сохраняет визуальную стабильность Masonry-сетки.