resize

При работе с динамическими интерфейсами часто возникает ситуация, когда размеры элементов внутри контейнера изменяются уже после их размещения. Причины могут быть различными: загрузка изображений, изменение контента, действия пользователя, анимации или адаптация интерфейса под разные размеры экрана. В таких случаях расположение элементов, рассчитанное библиотекой Packery, может нарушаться, если не выполнить повторный перерасчёт.

Библиотека Packery предоставляет механизм обновления раскладки, позволяющий корректно реагировать на изменение размеров элементов и контейнера. Управление пересчётом выполняется с помощью методов layout, shiftLayout, а также через интеграцию с внешними инструментами отслеживания изменения размеров.


Пересчёт расположения элементов

Основной способ обновления сетки — вызов метода layout(). Этот метод инициирует повторный расчёт расположения всех элементов внутри контейнера.

var pckry = new Packery('.grid', {
  itemSelector: '.grid-item',
  gutter: 10
});

pckry.layout();

Метод выполняет следующие действия:

  • определяет текущие размеры контейнера;
  • считывает размеры всех элементов;
  • вычисляет оптимальное положение каждого блока;
  • применяет новые координаты через CSS.

Использование layout() необходимо в ситуациях:

  • изменение размеров элементов;
  • добавление или удаление контента внутри блока;
  • загрузка изображений;
  • изменение размеров контейнера.

Метод shiftLayout

Метод shiftLayout() выполняет перерасчёт расположения элементов, но при этом сохраняет текущие позиции тех элементов, которые были перемещены вручную.

Это особенно важно при использовании drag-and-drop.

pckry.shiftLayout();

Отличия между методами:

Метод Поведение
layout() Полный перерасчёт сетки
shiftLayout() Сохранение текущих позиций перемещённых элементов

Если интерфейс содержит перетаскиваемые элементы, рекомендуется использовать именно shiftLayout().


Реакция на изменение размеров окна

Изменение размеров окна браузера влияет на ширину контейнера, что может требовать перерасчёта сетки. Packery поддерживает автоматическое обновление через параметр resize.

var pckry = new Packery('.grid', {
  itemSelector: '.grid-item',
  gutter: 10,
  resize: true
});

При значении resize: true библиотека автоматически выполняет layout() при изменении размера окна.

Однако при сложных интерфейсах иногда требуется ручной контроль.

window.addEventListener('resize', function() {
  pckry.layout();
});

Это позволяет:

  • добавить задержку (debounce);
  • синхронизировать пересчёт с другими компонентами интерфейса.

Отслеживание загрузки изображений

Частая причина изменения размеров элементов — загрузка изображений. До загрузки изображение не имеет окончательных размеров, из-за чего сетка может рассчитываться неправильно.

Для решения используется библиотека imagesLoaded.

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

var pckry = new Packery(grid, {
  itemSelector: '.grid-item'
});

imagesLoaded(grid, function() {
  pckry.layout();
});

Алгоритм работы:

  1. Packery инициализирует сетку.
  2. imagesLoaded отслеживает загрузку изображений.
  3. После загрузки выполняется layout().
  4. элементы занимают корректные позиции.

Пересчёт после изменения контента

Если содержимое элемента изменяется динамически (например, через AJAX или изменение текста), его размеры могут увеличиться или уменьшиться.

После изменения необходимо выполнить пересчёт:

element.textContent = "Новый текст";

pckry.layout();

Это гарантирует корректное перераспределение элементов.


Использование ResizeObserver

Современные браузеры поддерживают API ResizeObserver, позволяющий отслеживать изменение размеров элементов.

Интеграция с Packery может выглядеть следующим образом:

const resizeObserver = new ResizeObserver(() => {
  pckry.layout();
});

document.querySelectorAll('.grid-item').forEach(item => {
  resizeObserver.observe(item);
});

Принцип работы:

  1. ResizeObserver отслеживает изменение размеров элементов.
  2. при обнаружении изменений вызывается callback;
  3. выполняется layout().

Это обеспечивает автоматическую адаптацию сетки.


Адаптивная сетка

Изменение размеров элементов может быть связано с CSS media queries. Например:

.grid-item {
  width: 25%;
}

@media (max-width: 900px) {
  .grid-item {
    width: 50%;
  }
}

@media (max-width: 500px) {
  .grid-item {
    width: 100%;
  }
}

После изменения медиазапроса Packery должен пересчитать позиции элементов.

window.addEventListener('resize', function() {
  pckry.layout();
});

При использовании современных фреймворков иногда применяется requestAnimationFrame.

window.addEventListener('resize', () => {
  requestAnimationFrame(() => {
    pckry.layout();
  });
});

Это уменьшает вероятность множественных пересчётов.


Пересчёт при изменении размеров контейнера

Иногда меняется не сам элемент, а контейнер сетки. Например:

  • раскрытие боковой панели;
  • изменение ширины layout;
  • появление или скрытие меню.

В таком случае выполняется:

pckry.layout();

Пример:

document.querySelector('.sidebar-toggle')
  .addEventListener('click', function() {

  document.body.classList.toggle('sidebar-open');

  setTimeout(function() {
    pckry.layout();
  }, 300);

});

Задержка позволяет дождаться завершения CSS-анимации.


Изменение размеров элементов вручную

Иногда размеры элементов меняются программно:

item.style.width = "300px";
item.style.height = "200px";

pckry.layout();

Если размеры изменяются у нескольких элементов, рекомендуется выполнять пересчёт один раз.

items.forEach(item => {
  item.style.height = randomHeight() + "px";
});

pckry.layout();

Это значительно снижает нагрузку на браузер.


Производительность при частых изменениях размеров

Частые пересчёты могут создавать нагрузку на производительность. Для оптимизации применяются следующие подходы:

Debounce

let resizeTimer;

window.addEventListener('resize', function() {

  clearTimeout(resizeTimer);

  resizeTimer = setTimeout(function() {
    pckry.layout();
  }, 200);

});

Позволяет выполнять перерасчёт только после завершения изменения размеров окна.


Batch обновления

Если одновременно изменяется несколько элементов:

function updateItems() {

  items.forEach(item => {
    item.classList.toggle('large');
  });

  pckry.layout();

}

Изменения выполняются пакетно, а перерасчёт вызывается один раз.


requestAnimationFrame

Для плавности анимаций:

function relayout() {
  requestAnimationFrame(function() {
    pckry.layout();
  });
}

Это синхронизирует пересчёт с циклом рендеринга браузера.


Работа с CSS-трансформациями

Если размеры элементов меняются с помощью CSS-анимаций или трансформаций, Packery не всегда автоматически узнаёт об изменениях.

Например:

.grid-item.expanded {
  transform: scale(1.2);
}

После применения класса требуется перерасчёт.

item.classList.add('expanded');

setTimeout(function() {
  pckry.layout();
}, 300);

Задержка соответствует длительности анимации.


Использование MutationObserver

Если элементы внутри сетки изменяются автоматически (например, при работе CMS или сторонних скриптов), можно использовать MutationObserver.

const observer = new MutationObserver(() => {
  pckry.layout();
});

observer.observe(document.querySelector('.grid'), {
  childList: true,
  subtree: true
});

Наблюдатель реагирует на:

  • добавление элементов;
  • удаление элементов;
  • изменение DOM-структуры.

Типичный сценарий динамической сетки

В современных интерфейсах часто используется комбинация нескольких механизмов:

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

var pckry = new Packery(grid, {
  itemSelector: '.grid-item',
  gutter: 10
});

imagesLoaded(grid, function() {
  pckry.layout();
});

window.addEventListener('resize', debounce(function() {
  pckry.layout();
}, 200));

const resizeObserver = new ResizeObserver(() => {
  pckry.layout();
});

document.querySelectorAll('.grid-item')
  .forEach(item => resizeObserver.observe(item));

Такая архитектура обеспечивает:

  • корректное отображение изображений;
  • адаптацию при изменении размеров окна;
  • автоматическое реагирование на изменение размеров элементов;
  • стабильную работу динамической сетки.

Основные методы работы с resize

Метод Назначение
layout() полный перерасчёт сетки
shiftLayout() перерасчёт с сохранением позиций
resize: true автоматический пересчёт при изменении окна
ResizeObserver отслеживание изменения размеров элементов
imagesLoaded пересчёт после загрузки изображений

Корректная обработка изменения размеров элементов является важной частью работы с Packery. Без неё динамические интерфейсы, содержащие изображения, анимации и изменяемый контент, могут нарушать структуру сетки и приводить к наложению элементов.