[Из песочницы] Отслеживаем ресайзинг элемента без setTimeout и фреймов

Наверно каждый WEB-разработчик когда-либо сталкивался с проблемой отслеживания события resize на странице. И если для window это сделать сможет любой новичок, то для остальных элементов эта задача принесет немало головной боли. Если вы относитесь к этой категории людей, то добро пожаловать под кат.

В интернете есть много статей где эта проблема решается с помощью setInterval или, в лучшем случае, рекурсивного setTimeout, который постоянно через определенные промежутки времени проверяет не изменились ли размеры указанного элемента. Но в большинстве случаев размеры элемента изменяются очень редко, поэтому такой способ является неприемлемым и к тому же может приводить к излишним тратам памяти.

На Хабре я нашел решение для отслеживания «onresize» на элементе путем добавления внутрь него фрейма. Этот способ рабочий и в большинстве случаев наверняка будет полезен. Но что делать если по какой-то причине не хочется добавлять лишний фрейм внутрь элемента? Я хочу предложить еще пару способов для отслеживания изменения размеров элемента.

Для начала я разобью случаи в которых изменяются размеры элемента на категории:

  • Изменение содержимого элемента
  • Изменение стилей элемента

Первый способ: DOMSubtreeModified


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

Для этого нет необходимости наблюдать за изменением размеров элемента средствами CSS, а достаточно лишь отследить изменение структуры DOM внутри элемента.

Это можно легко осуществить используя событие DOMSubtreeModified, которое срабатывает всякий раз когда структура или текст внутри элемента изменяется:

el.addEventListener("DOMSubtreeModified", function (e) {
  console.log("Размеры элемента: " + el.clientWidth + " X " + el.clientHeight);
}, false);

→ Поддержка браузерами

Второй способ: transitionend


Для того чтобы отследить изменение размеров через CSS придется добавить целевому элементу следующие стили:
#el {
  /* Свойства изменение которых необходимо отслеживать */
  transition-property: width, height, padding;

  /* Устанавливаем "незаметную для глаза" длительность перехода */
  transition-duration: 1ms;
}

Список свойств, как и длительность перехода можно подобрать под себя. Вполне возможно, что какие-то из этих свойств у элемента уже заданы.

Теперь мы можем отследить событие transitionend, которое срабатывает, когда CSS transition закончил свое выполнение:

el.addEventListener("transitionend", function () {
  console.log("Размеры элемента: " + el.clientWidth + " X " + el.clientHeight);
}, false);

→ Поддержка браузерами

К сожалению нет свойства transitionstart и transition или transitioninterval, поэтому событие срабатывает только по окончании перехода, так что значение transition-duration следует выбирать небольшое. Но если установить transition-duration равное 0, то событие не будет срабатывать вовсе.

Заключение


Конечно эти способы не смогут помочь в любой ситуации, но думаю в большинстве случаев первого или второго способа (а может и обоих сразу) будет более чем достаточно.

Надеюсь эта статья окажется полезной. Буду рад обоснованной критике, так как это мой первый опыт на Хабре.

→ Пример на JSFiddle

Комментарии (2)

  • 11 апреля 2017 в 07:55

    0

    А что мешает привязать отслеживание размеров элемента к тем действиям, которые приводят к изменению его размеров? С window понятно, там действия внешние, но элементы сами по себе не меняются в размере.
    • 11 апреля 2017 в 08:11

      0

      В статье речь как раз и идет о том, чтобы отслеживать действия которые приводят к изменению размеров элемента.
      Тут приводится лишь 2 дополнительных способа. Если вы точно знаете когда размеры элемента могут измениться, то вы можете отслеживать это другим способом.
      Например если вы делаете плагин слайдера, то можно проверять высоту при переключении слайдов.
      Но если пользователь вашего плагина поместит на слайд какой-нибудь опрос, в котором при нажатии на кнопку будут раскрываться результаты (и соответственно изменяться высота контента), то ему надо будет еще раз вручную инициировать пересчет высоты слайдера.

© Habrahabr.ru