Cómo animar a tamaños intrínsecos

Funciones web: calc-size() interpolate-size

La animación de elementos a tamaños dinámicos, como block-size: auto o inline-size: max-content, históricamente requería JavaScript o hacks frágiles de "max-height". La propiedad interpolate-size y la función calc-size() permiten que el navegador interpole de forma nativa entre longitudes fijas y palabras clave de tamaño intrínseco.

Pasos de implementación

  1. Habilita la interpolación de palabras clave: Aplica interpolate-size: allow-keywords a un elemento superior (por lo general, :root) para habilitar las transiciones de propiedades que usan palabras clave intrínsecas.
  2. Define la transición: Establece un transition para la propiedad de tamaño (p.ej., block-size, inline-size) en el elemento de destino.
  3. Usa palabras clave intrínsecas: Cambia la propiedad de tamaño a una palabra clave intrínseca compatible (auto, min-content, max-content, fit-content o, para flex-basis, content) durante una interacción (p.ej., :hover o una clase de estado).
  4. Realiza cálculos (opcional): Usa calc-size() si necesitas realizar operaciones matemáticas en un tamaño intrínseco (p.ej., auto + 2rem). calc-size() también admite la palabra clave any para cálculos independientes de la base.

Ejemplo: Patrón de expansión genérico

Puedes aplicar este patrón a cualquier contenedor (como una sección "Mostrar más" o un menú de navegación) para realizar la transición entre una altura restringida y el tamaño natural del elemento.

/* 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;
}

Ejemplo: Tamaño de línea intrínseco calculado

.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);
}

Ejemplo: Transición de intrínseco a fijo

También puedes animar en la dirección opuesta: comenzar desde un tamaño natural y contraer hasta una longitud específica. Esto es útil para los componentes "descartables".

.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);
});

Restricciones clave

  • Restricción de palabra clave a palabra clave: No puedes animar entre dos palabras clave diferentes directamente (p.ej., de min-content a max-content). Un extremo de la transición debe ser una longitud o un porcentaje fijos (p.ej., de 0 a auto).
  • Sintaxis de calc-size: Dentro de calc-size(), no puedes mezclar diferentes palabras clave intrínsecas en la misma expresión. El primer argumento (la base) define lo que representa size.
  • Requisito de habilitación: Las transiciones a palabras clave intrínsecas están inhabilitadas de forma predeterminada (numeric-only) para mantener la retrocompatibilidad. Debes aplicar interpolate-size: allow-keywords al elemento o a un elemento superior. calc-size() actúa como una anulación por propiedad, lo que habilita automáticamente la interpolación cada vez que se usa.

Estrategias de resguardo

interpolate-size y calc-size() son mejoras progresivas. Los navegadores que no las admitan realizarán un salto instantáneo al tamaño objetivo.

  • Degradación elegante: En el caso de las transiciones simples de block-size: auto, los navegadores estándar simplemente alternarán el tamaño de forma instantánea, lo que es funcional, pero menos refinado.
  • Resguardos manuales de palabras clave: Cuando uses calc-size(), proporciona siempre un resguardo de palabra clave estándar para los navegadores más antiguos, ya que descartarán toda la declaración 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;
}