Анимация до встроенных размеров

Веб-функции: calc-size() interpolate-size

Для анимации элементов до динамических размеров, таких как block-size: auto или inline-size: max-content, ранее требовался JavaScript или ненадежные хаки max-height. Свойство interpolate-size и функция calc-size() позволяют браузеру нативно интерполировать фиксированные длины и ключевые слова для внутренних размеров.

Реализация

  1. Включите интерполяцию ключевых слов. Примените interpolate-size: allow-keywords к родительскому элементу (обычно :root), чтобы включить переходы для свойств, использующих внутренние ключевые слова.
  2. Определите переход. Задайте transition для свойства размера (например, block-size, inline-size) в целевом элементе.
  3. Используйте внутренние ключевые слова. Измените свойство размера на поддерживаемое внутреннее ключевое слово (auto, min-content, max-content, fit-content или content для flex-basis) во время взаимодействия (например, :hover или класс состояния).
  4. Выполняйте вычисления (необязательно). Используйте calc-size(), если вам нужно выполнить математические вычисления с внутренним размером (например, auto + 2rem). calc-size() также поддерживает ключевое слово any для вычислений, не зависящих от основы.

Пример: шаблон общего расширения

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

/* Opt-in globally for all children */
:root {
  /* MANDATORY: Transitions to intrinsic keywords are disabled by default for compatibility */
  interpolate-size: allow-keywords;
}

.expandable-container {
  /* 1. Define a fixed initial size (or 0) and hide overflow */
  block-size: 100px;
  overflow: hidden;
  
  /* 2. Transition the sizing property */
  transition: block-size 0.4s ease-out;
}

.expandable-container.is-expanded {
  /* 3. Smoothly animate to the intrinsic natural height */
  block-size: auto;
}

Пример: вычисленный внутренний размер строки

.badge {
  inline-size: 40px;
  overflow: hidden;
  white-space: nowrap;
  transition: inline-size 0.3s ease;
}

.badge:hover {
  /* calc-size(basis, calculation) */
  /* 'size' refers to the evaluated basis (max-content in this case) */
  inline-size: calc-size(max-content, size + 20px);
}

Пример: переход от intrinsic к fixed

Вы также можете анимировать объект в обратном направлении – от естественного размера до определенной длины. Это полезно для компонентов, которые можно закрыть.

.collapsible-alert {
  /* 1. Start with the natural content height */
  block-size: auto;
  overflow: hidden;
  transition: block-size 0.5s ease-in-out, opacity 0.5s ease;
}

.collapsible-alert.is-dismissed {
  /* 2. Smoothly collapse to zero */
  block-size: 0;
  opacity: 0;
  pointer-events: none;
}

/* MANDATORY Copy-Paste Safety: Disable sizing animations for sensitive users */
@media (prefers-reduced-motion: reduce) {
  .expandable-container,
  .badge,
  .collapsible-alert {
    transition: none !important;
  }
}
// MANDATORY Accessibility Synchronization: Ensure elements collapsed to zero dimensions are removed from the assistive technology tree, and sync aria-expanded states on triggers.
const alertElement = document.querySelector('.collapsible-alert');
alertElement.addEventListener('transitionend', (e) => {
  if (e.propertyName === 'block-size' && alertElement.classList.contains('is-dismissed')) {
    alertElement.hidden = true;
  }
});

// Example trigger syncer
const triggerBtn = document.querySelector('.accordion-trigger');
triggerBtn?.addEventListener('click', () => {
  const isExpanded = triggerBtn.getAttribute('aria-expanded') === 'true';
  triggerBtn.setAttribute('aria-expanded', !isExpanded);
});

Основные ограничения

  • Ограничение на переход между ключевыми словами. Нельзя напрямую анимировать переход между двумя разными ключевыми словами (например, от min-content к max-content). Одно из значений должно быть фиксированной длиной или процентом (например, от 0 к auto).
  • Синтаксис calc-size. Внутри calc-size() нельзя использовать разные внутренние ключевые слова в одном выражении. Первый аргумент (основание) определяет, что представляет собой size.
  • Требование о согласии. Переход на внутренние ключевые слова по умолчанию отключен (numeric-only) для обеспечения обратной совместимости. Примените interpolate-size: allow-keywords к элементу или его предку. calc-size() переопределяет настройки для каждого свойства, автоматически включая интерполяцию при использовании.

Резервные стратегии

interpolate-size и calc-size() – это прогрессивные улучшения. В браузерах, которые не поддерживают такие переходы, размер будет меняться мгновенно.

  • Постепенное сокращение. Для простых переходов block-size: auto стандартные браузеры будут просто мгновенно переключать размер, что функционально, но менее отточено.
  • Резервные ключевые слова, заданные вручную. При использовании calc-size() всегда указывайте стандартное резервное ключевое слово для старых браузеров, поскольку они будут игнорировать всю декларацию calc-size().
.card {
  block-size: auto; /* Fallback for older browsers */
  block-size: calc-size(auto, size); /* Modern browsers use this */
  transition: block-size 0.3s ease;
}