Animer vers des tailles intrinsèques

Fonctionnalités Web : calc-size() interpolate-size

L'animation d'éléments vers des tailles dynamiques telles que block-size: auto ou inline-size: max-content nécessitait auparavant du code JavaScript ou des astuces "max-height" fragiles. La propriété interpolate-size et la fonction calc-size() permettent au navigateur d'interpoler de manière native entre des longueurs fixes et des mots clés de dimensionnement intrinsèque.

Procédure d'implémentation

  1. Activer l'interpolation de mots clés : appliquez interpolate-size: allow-keywords à un élément parent (généralement :root) pour activer les transitions pour les propriétés utilisant des mots clés intrinsèques.
  2. Définissez la transition : définissez une transition pour la propriété de dimensionnement (par exemple, block-size, inline-size) sur l'élément cible.
  3. Utiliser des mots clés intrinsèques : remplacez la propriété de dimensionnement par un mot clé intrinsèque compatible (auto, min-content, max-content, fit-content ou (pour flex-basis) content) lors d'une interaction (par exemple, :hover ou une classe d'état).
  4. Effectuer des calculs (facultatif) : utilisez calc-size() si vous devez effectuer des calculs sur une taille intrinsèque (par exemple, auto + 2rem). calc-size() accepte également le mot clé any pour les calculs indépendants de la base.

Exemple : Modèle d'expansion générique

Vous pouvez appliquer ce modèle à n'importe quel conteneur (comme une section "Afficher plus" ou un menu de navigation) pour passer d'une hauteur limitée à la taille naturelle de l'élément.

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

Exemple : Taille inline intrinsèque calculée

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

Exemple : Passer d'une taille intrinsèque à une taille fixe

Vous pouvez également animer dans la direction opposée, en commençant par une taille naturelle et en réduisant à une longueur spécifique. Cela est utile pour les composants "pouvant être ignorés".

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

Principales contraintes

  • Restriction de mot clé à mot clé : vous ne pouvez pas animer directement entre deux mots clés différents (par exemple, de min-content à max-content). Une extrémité de la transition doit être une longueur ou un pourcentage fixe (par exemple, de 0 à auto).
  • Syntaxe calc-size : dans calc-size(), vous ne pouvez pas mélanger différents mots clés intrinsèques dans la même expression. Le premier argument (la base) définit ce que représente size.
  • Exigence d'activation : les transitions vers des mots clés intrinsèques sont désactivées par défaut (numeric-only) pour maintenir la rétrocompatibilité. Vous devez appliquer interpolate-size: allow-keywords à l'élément ou à un ancêtre. calc-size() agit comme un remplacement par propriété, en activant automatiquement l'interpolation chaque fois qu'elle est utilisée.

Stratégies de remplacement

interpolate-size et calc-size() sont des améliorations progressives. Les navigateurs qui ne les prennent pas en charge passeront instantanément à la taille cible.

  • Dégradation élégante : pour les transitions block-size: auto simples, les navigateurs standards basculent simplement la taille instantanément, ce qui est fonctionnel, mais moins soigné.
  • Mots clés de remplacement manuels : lorsque vous utilisez calc-size(), fournissez toujours un mot clé de remplacement standard pour les anciens navigateurs, car ils ignoreront l'intégralité de la déclaration 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;
}