При использовании библиотеки Masonry для организации сеток элементов часто возникает ситуация, когда некоторые изображения загружаются дольше других. Поскольку Masonry рассчитывает позиции элементов на основе их размеров в момент инициализации, незагруженные изображения могут приводить к некорректному расположению блоков, перекрытиям или пустым промежуткам в сетке.
Masonry ориентируется на текущие размеры элементов DOM в момент
вызова masonry.layout() или при инициализации через
new Masonry(). Если изображение ещё не загружено, его
высота и ширина могут быть равны нулю или значительно меньше реальных,
что нарушает вычисление столбцов и позиционирование соседних блоков. Это
особенно критично для сеток с разной высотой элементов
(grid with variable heights), где точность расчётов
напрямую зависит от реальных размеров контента.
load для изображенийКаждое изображение можно отслеживать через событие load,
чтобы Masonry вызывал перерасчёт сетки после полной загрузки.
Пример:
const grid = document.querySelector('.grid');
const msnry = new Masonry(grid, {
itemSelector: '.grid-item',
columnWidth: '.grid-sizer',
percentPosition: true
});
const images = grid.querySelectorAll('img');
images.forEach(img => {
img.addEventListener('load', () => {
msnry.layout();
});
});
Преимущество этого метода — перерасчёт выполняется только после загрузки конкретного изображения, что уменьшает визуальные артефакты.
imagesLoadedБолее надёжный подход — интеграция Masonry с библиотекой imagesLoaded. Она отслеживает загрузку всех изображений внутри контейнера и позволяет выполнять действия после полной загрузки:
imagesLoaded(grid, function() {
msnry.layout();
});
imagesLoaded создаёт колбэк, который
вызывается, когда все изображения полностью загружены.Если заранее известны размеры изображений, можно установить их через
атрибуты width и height или CSS. Это позволит
Masonry корректно рассчитать позиции блоков даже до загрузки
изображений:
<img src="photo.jpg" width="300" height="200" alt="Photo">
.grid-item img {
display: block;
width: 100%;
height: auto;
}
При реализации бесконечной прокрутки (infinite scroll)
необходимо повторно вызывать msnry.appended() и
msnry.layout() после загрузки новых элементов и их
изображений:
fetch('/api/photos')
.then(response => response.json())
.then(data => {
const items = data.map(photo => {
const div = document.createElement('div');
div.className = 'grid-item';
div.innerHTML = `<img src="${photo.url}" width="${photo.width}" height="${photo.height}">`;
return div;
});
items.forEach(item => grid.appendChild(item));
imagesLoaded(items, function() {
msnry.appended(items);
});
});
Для сеток с сотнями элементов частые вызовы layout() при
каждой загрузке изображения могут быть ресурсоёмкими. В таких случаях
рекомендуется:
function debounce(fn, delay) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(fn, delay);
};
}
const debouncedLayout = debounce(() => msnry.layout(), 100);
images.forEach(img => img.addEventListener('load', debouncedLayout));
layout() для группы изображений
вместо индивидуальных вызовов.load для отдельных изображений или
использование imagesLoaded решает большинство
проблем.msnry.appended() и msnry.layout().layout() критична для
производительности больших сеток.Эти методы совместно позволяют создавать стабильные и предсказуемые сетки Masonry даже при работе с асинхронно загружаемыми изображениями.