Как отслеживать размер блока через ResizeObserver без циклов

ResizeObserver сообщает об изменении размеров элемента. Выберите область измерения, подключите наблюдение и проверьте, что обработчик не меняет размер по кругу.
Что должно получиться
Панель с диаграммой может сузиться, когда рядом раскрыли меню, хотя окно браузера осталось прежним. Событие изменения окна не описывает все такие ситуации. ResizeObserver позволяет следить за конкретным элементом и передать его новые размеры коду, которому они действительно нужны.
Если требуется лишь поменять расположение текста и картинки при сужении карточки, сначала рассмотрите CSS. Наблюдатель полезен там, где размер нужен логике JavaScript.
Из чего это складывается
| Часть | Для чего нужна | Что уточнить |
|---|---|---|
| Наблюдаемый элемент | Определяет источник размеров | Нужен контейнер, а не случайный сосед |
| Измеряемая область | Задаёт, какие изменения отслеживаются | Содержимое или область вместе с отступами и рамкой |
| Обработчик | Получает записи об изменениях | Может получить несколько записей за один вызов |
| Действие компонента | Использует полученную величину | Не должно бесконтрольно менять собственный источник размеров |
| Отключение | Завершает наблюдение | Отдельно для одного элемента или сразу для всех |
По умолчанию observe следит за content-box. Для обычного HTML-элемента это область содержимого без внутренних отступов и рамки. Вариант border-box учитывает и содержимое, и padding, и border. Выберите область по задаче, а затем используйте соответствующие данные из записи наблюдения.
Как это сделать по шагам
- Сформулируйте действие. Запишите, кто потребляет размер и зачем: например, область рисования должна помещаться внутри панели. Смена цвета фона сама по себе измерений не требует.
- Выберите стабильный контейнер. Найдите элемент после его появления на странице. Проверьте, что ссылка на него существует и относится к нужному экземпляру компонента.
- Начните с чтения. Создайте ResizeObserver, переберите полученные entries и временно выводите размер в консоль. Не изменяйте стили в первом проверочном варианте.
- Подключите наблюдение. Передайте элемент в observe. Для варианта с border-box явно укажите эту область в параметрах и читайте подходящие размеры.
- Воспроизведите изменение без сужения окна. Раскройте боковую панель, замените короткий текст длинным или измените ширину родительского блока. Сопоставьте числа с выбранной областью.
- Добавьте действие без обратной связи. Передавайте размер потребителю. Если действие затрагивает геометрию наблюдаемого элемента, предусмотрите устойчивое конечное состояние и проверку перед записью.
- Завершите жизненный цикл. При удалении компонента вызовите unobserve для отдельной цели либо disconnect, если наблюдатель больше нигде не используется.
Минимальный пример для проверки
Пусть переменная target уже содержит найденный HTML-элемент. Начальный вариант: const watcher = new ResizeObserver(entries => { for (const entry of entries) { console.log(entry.contentRect.width); } }); watcher.observe(target); Здесь обработчик только читает ширину содержимого и ничего не перестраивает.
Частые ошибки
Прибавлять размер при каждом уведомлении
Представьте обработчик, который читает текущую ширину и каждый раз делает её немного больше. Изменение порождает новое уведомление, а оно — следующую прибавку. У такой зависимости нет конечного состояния. Браузер может отложить часть уведомлений и сообщить о цикле, но это не исправляет причину роста.
Отделите размер внешнего контейнера от размера рисуемого содержимого. Если запись в геометрию необходима, сравнивайте желаемое состояние с уже установленным и не повторяйте одинаковую запись без причины. Проверьте также косвенную цепочку: размер потомка меняет родителя, а родитель снова меняет потомка.
Считать requestAnimationFrame лекарством от любого цикла
Перенос записи на следующий кадр меняет момент выполнения. Он не отменяет зависимость «новый размер снова вызывает увеличение». Блок может продолжить расти по кадрам, даже если конкретное предупреждение исчезло. Сначала устраните бесконечную логику, затем решайте, когда удобнее обновлять представление.
Смешивать геометрию и появление в области просмотра
ResizeObserver не является счётчиком прочтений и не сообщает, что посетитель заметил карточку. Для пересечения с областью просмотра существует другой механизм. Блок может изменить ширину за пределами экрана, а может войти в экран с прежними размерами.
Как проверить
- Известно, какой элемент наблюдается и почему выбран именно он.
- Размер содержимого не подписан как размер вместе с отступами и рамкой.
- Изменение панели при неизменном окне вызывает ожидаемую реакцию.
- Вызов обрабатывает все нужные записи, а не случайно только первую.
- После прекращения изменений интерфейс приходит к устойчивому состоянию.
- Консоль не заполняется повторяющимися предупреждениями о цикле.
- Удаление и повторное создание компонента не удваивает работу.
- Без необязательного улучшения основной текст и действия остаются доступны.
Для изменения оформления без JavaScript подойдут CSS container queries. Не путайте размер с пересечением блока с областью просмотра. Повторяющиеся сообщения разбирайте через консоль браузера. Если нужна доработка компонента, опишите её в разделе разработки.
Вопросы и ответы
Можно ли заменить наблюдатель событием resize у окна?
Только если размер элемента зависит именно от окна и других причин изменения у задачи нет. Раскрытие соседней панели или изменение содержимого может изменить блок при прежнем размере окна.
Входит ли padding в contentRect.width?
У обычного HTML-элемента эта величина относится к области содержимого и не включает padding и рамку. Для другой области выбирайте подходящий режим наблюдения и соответствующее поле записи.
Почему обработчик вызывается сразу после подключения?
Начальное уведомление позволяет получить исходную геометрию наблюдаемого элемента. Не считайте каждый вызов следствием действия пользователя: проверяйте размер и состояние компонента.
Уберёт ли requestAnimationFrame бесконечное увеличение?
Нет, сам по себе перенос работы не создаёт конечного условия. Если код каждый раз увеличивает наблюдаемый размер, цепочка может продолжаться и между кадрами.
Когда вызывать unobserve, а когда disconnect?
unobserve завершает наблюдение за указанным элементом. disconnect прекращает наблюдение за всеми целями данного экземпляра; его удобно использовать, когда весь этот наблюдатель больше не нужен.
Нужен ли ResizeObserver для обычной адаптивной карточки?
Не обязательно. Если требуется только менять стили по доступному месту, начните с CSS container queries. Наблюдатель добавляйте, когда размер должен использовать код компонента.
