При работе с динамическими элементами, особенно содержащими изображения, часто возникает ситуация, когда JavaScript-код выполняется до их полной загрузки. Это приводит к некорректным расчетам:
-
Неверная высота блоков – изображения еще не загружены, и
outerHeight()возвращает неправильные значения. -
Неточное позиционирование –
offset()может давать ошибочные координаты, если DOM изменится после загрузки картинок. -
"Прыгающие" элементы – например, плавающая корзина исчезает раньше времени из-за неучтенных изображений.
Решение: отслеживание загрузки всех изображений
1. Базовый вариант с jQuery
$(function() {
function onImageLoad() {
loadedCount++;
if (loadedCount === totalImages) {
// Все изображения загружены
const offset = $('.block').offset();
const height = $('.block').outerHeight(true);
console.log('Готово!', offset, height);
}
}
const $images = $('img'); // Или конкретный контейнер: $('.gallery img')
const totalImages = $images.length;
let loadedCount = 0;
$images.each(function() {
if (this.complete) {
onImageLoad(); // Уже загружено
} else {
$(this).on('load error', onImageLoad); // Ждем загрузки или ошибки
}
});
});Как это работает:
-
Считаем общее количество изображений (
totalImages). -
Для каждого изображения проверяем, загружено ли оно (
this.complete). -
Если нет – подписываемся на события
loadиerror. -
Как только счетчик
loadedCountдостигаетtotalImages, выполняем нужный код.
2. Улучшенная версия с Promise (ES6+)
function waitForImages(selector) {
const $elements = $(selector);
const promises = $elements.map(function() {
if (this.complete) return Promise.resolve();
return new Promise((resolve) => {
$(this).on('load error', resolve);
});
}).get();
return Promise.all(promises);
}
// Использование
waitForImages('img').then(() => {
console.log('Все изображения загружены!');
const height = $('.container').outerHeight();
});Плюсы:
-
Чище и современнее.
-
Легко интегрируется с другими асинхронными операциями.
3. Готовые библиотеки
Для сложных случаев (например, lazy load или динамически добавляемые изображения) используйте:
Пример с imagesLoaded:
imagesLoaded(document.querySelectorAll('img'), () => {
console.log('Готово!');
});Дополнительные рекомендации
1. Оптимизация для больших галерей
Если изображений много, ограничьте область проверки:
const $images = $('.product-gallery img'); // Только в конкретном блоке2. CSS-хаки для предотвращения "прыжков"
Добавьте в CSS для стабилизации верстки:
img {
display: block;
width: 100%;
height: auto;
}3. Анимации только после загрузки
Чтобы избежать "дерганий", инициализируйте анимации после waitForImages():
waitForImages('.hero img').then(() => {
$('.hero').fadeIn(500); // Показываем только после загрузки
});Итог
-
Для простых случаев – используйте базовый вариант с счетчиком.
-
Для современных проектов – переходите на
Promise. -
Для сложных сценариев – подключайте
imagesLoaded.
Это гарантирует, что ваш код выполнится только тогда, когда все изображения готовы, и верстка стабилизировалась.