Как работает свойство interpolate-size в CSS и почему оно позволяет плавно анимировать переход к height: auto.

Анимация height: auto через interpolate-size

Долгое время height: auto считалось «неанимируемым»: браузер знал начальное значение, но не мог вычислить промежуточные между фиксированной длиной и высотой, зависящей от содержимого. Свойство interpolate-size снимает это ограничение.

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

Свойство interpolate-size переносит решение задачи на уровень CSS. Оно сообщает браузеру, что размеры можно интерполировать не только между числовыми значениями, но и между числом и ключевым словом вроде auto, min-content или fit-content.

Проблема, которую решает свойство

По умолчанию браузер интерполирует только числовые значения: 0px → 200px, 1rem → 2rem. Ключевые слова не имеют числового представления до момента вычисления стилей, поэтому переход height: 0 → height: auto раньше просто не анимировался: значение менялось скачком.

Свойство interpolate-size разрешает браузеру вычислить внутренний размер элемента в момент перехода и построить плавную кривую между начальным числом и этим вычисленным размером.

/* Без interpolate-size переход мгновенный */
.card {
  height: 0;
  transition: height 0.4s;
}
.card:hover {
  height: auto; /* значение применится скачком */
}

Синтаксис и значения

Свойство наследуется, поэтому его удобно задавать на :root. Оно принимает два значения.

  • numeric-only — значение по умолчанию. Интерполируются только числовые длины и проценты.
  • allow-keywords — разрешает интерполяцию между длиной и внутренним размером (auto, min-content, max-content, fit-content).
:root {
  interpolate-size: allow-keywords;
}

Поскольку свойство наследуемое, установка на корневом элементе распространяет поведение на весь документ. При необходимости можно переопределить его на отдельном поддереве.

Базовый пример: раскрывающаяся карточка

Классический сценарий — карточка, которая увеличивает высоту при наведении. Раньше приходилось задавать max-height с запасом, из-за чего переход завершался раньше, чем заканчивалась видимая анимация.

:root {
  interpolate-size: allow-keywords;
}

.card {
  height: 30px;
  overflow: hidden;
  transition: height 0.4s ease;
  background: #f0f0f0;
  border: 1px solid #ccc;
  padding: 8px;
}

.card:hover {
  height: auto;
}

В момент наведения браузер измеряет фактическую высоту содержимого и плавно переходит к ней. Длительность 0.4s относится ко всему переходу, а не к условному max-height.

Анимация к другим внутренним размерам

Свойство работает не только с auto. Оно поддерживает переходы к min-content, max-content и fit-content. Это полезно, когда нужно раскрыть элемент ровно под содержимое или, наоборот, ограничить его минимально возможной шириной.

:root {
  interpolate-size: allow-keywords;
}

.panel {
  width: 100px;
  transition: width 0.3s ease;
}

.panel:hover {
  width: fit-content;
}

В этом примере ширина плавно меняется от фиксированных 100px до размера, который определяется содержимым панели.

interpolate-size управляет не конкретным свойством, а правилом интерполяции для всего документа. Это глобальная настройка поведения анимации, а не локальный модификатор.

Ограничения и тонкости

Не всякая комбинация ключевых слов анимируется. Спецификация допускает интерполяцию между длиной и внутренним размером, но не между двумя разными внутренними размерами. Переход min-content → max-content останется мгновенным, поскольку оба значения являются ключевыми словами.

Также стоит учитывать, что интерполяция к auto требует вычисления внутреннего размера на каждом кадре анимации. Для сложных многоуровневых структур это может сказаться на производительности, поэтому злоупотреблять таким переходом в больших списках не стоит.

Связь с calc-size()

Функция calc-size() решает смежную задачу: она позволяет выполнять математические операции над внутренними размерами, например calc-size(auto, size + 20px). В отличие от interpolate-size, она включается не глобально, а локально в конкретном свойстве и автоматически разрешает интерполяцию для этого значения.

.card {
  height: 30px;
  transition: height 0.4s ease;
}

.card:hover {
  height: calc-size(auto, size + 20px);
}

Выбор между двумя инструментами прост: если нужна только плавная анимация к auto, достаточно interpolate-size. Если же над внутренним размером требуется арифметика, применяется calc-size().

Что запомнить

  • interpolate-size разрешает анимацию между числовыми длинами и ключевыми словами размеров.
  • По умолчанию действует numeric-only; для анимации к auto нужно allow-keywords.
  • Свойство наследуется и обычно задаётся на :root.
  • Поддерживаются переходы к auto, min-content, max-content, fit-content.
  • Переход между двумя ключевыми словами не интерполируется.
  • Анимация к auto вычисляет внутренний размер на каждом кадре — учитывайте это в тяжёлых структурах.
  • Для арифметики над внутренним размером используйте calc-size().
  • Оба инструмента устраняют потребность в трюке с max-height и в измерении высоты через JavaScript.