Utilisez la propriété interpolate-size
ou la fonction calc-size()
pour activer des transitions et des animations fluides entre les longueurs et les mots clés de dimensionnement intrinsèque, et inversement.
Publié le 17 septembre 2024
Introduction
Une fonctionnalité CSS souvent demandée est la possibilité d'animer vers height: auto
. Une légère variation de cette requête consiste à passer à la propriété width
au lieu de height
, ou à passer à l'une des autres tailles intrinsèques représentées par des mots clés tels que min-content
, max-content
et fit-content
.
Par exemple, dans la démonstration suivante, il serait souhaitable que les libellés passent progressivement à leur largeur naturelle lorsque vous pointez sur les icônes.
Le CSS utilisé est le suivant:
nav a {
width: 80px;
overflow-x: clip;
transition: width 0.35s ease; /* 👈 Transition the width */
&:hover,
&:focus-visible {
width: max-content; /* 👈 Doesn't work with transitions */
}
}
Même si un transition
est déclaré pour effectuer la transition de la propriété width
et que width: auto
est déclaré sur :hover
, aucune transition fluide ne se produit. Au lieu de cela, le changement est brutal.
Animer vers et depuis des mots clés de dimensionnement intrinsèque avec interpolate-size
La propriété CSS interpolate-size
vous permet de contrôler si les animations et les transitions des mots clés de dimensionnement intrinsèque CSS doivent être autorisées ou non.
Sa valeur par défaut est numeric-only
, ce qui désactive l'interpolation. Lorsque vous définissez la propriété sur allow-keywords
, vous activez les interpolations des longueurs vers les mots clés de dimensionnement intrinsèque CSS lorsque le navigateur peut animer ces mots clés.
Conformément aux spécifications:
numeric-only
: un<intrinsic-size-keyword>
ne peut pas être interpolé.allow-keywords
: deux valeurs peuvent être interpolées si l'une d'elles est un<intrinsic-size-keyword>
et l'autre un<length-percentage>
. […]
Étant donné que la propriété interpolate-size
est héritée, vous pouvez la déclarer sur :root
pour permettre la transition entre les mots clés de dimensionnement intrinsèque et l'ensemble du document. Il s'agit de l'approche recommandée.
/* Opt-in the whole page to interpolate sizes to/from keywords */
:root {
interpolate-size: allow-keywords; /* 👈 */
}
Dans la démonstration suivante, cette règle est ajoutée au code. Par conséquent, les animations vers et depuis width: auto
fonctionnent correctement (dans les navigateurs compatibles):
Limiter la couverture de l'acceptation en réduisant le sélecteur
Si vous souhaitez limiter l'activation de allow-keywords
à un sous-arbre de votre document, ajustez le sélecteur de :root
à l'élément que vous souhaitez cibler. Par exemple, si l'élément <header>
de votre page n'est pas compatible avec ce type de transitions, vous pouvez limiter l'activation à l'élément <main>
et à ses descendants comme suit:
main { /* 👈 Scope the opt-in to only <main> and its descendants */
interpolate-size: allow-keywords;
}
Pourquoi ne pas autoriser l'animation vers et depuis les mots clés de dimensionnement par défaut ?
Les commentaires les plus courants concernant ce mécanisme d'activation sont les suivants : les navigateurs ne devraient autoriser que les transitions et les animations des mots clés de dimensionnement intrinsèque vers des longueurs par défaut.
L'option permettant d'activer ce comportement a été étudiée lors du développement de la fonctionnalité. Le groupe de travail a découvert que l'activation de cette fonctionnalité par défaut n'est pas rétrocompatible, car de nombreuses feuilles de style supposent que les mots clés de dimensionnement intrinsèque (tels que auto
ou min-content
) ne peuvent pas être animés. Vous trouverez plus d'informations dans ce commentaire sur le problème du groupe de travail CSS concerné.
Par conséquent, la propriété est activée. Grâce à sa caractéristique d'héritage, l'activation d'un document entier ne consiste qu'en une déclaration interpolate-size: allow-sizes
sur :root
, comme indiqué précédemment.
Animer vers et depuis des mots clés de dimensionnement intrinsèque avec calc-size()
Vous pouvez également activer l'interpolation à partir et vers les mots clés de dimensionnement intrinsèque à l'aide de la fonction calc-size()
. Il permet d'effectuer des calculs mathématiques sur des tailles intrinsèques de manière sûre et bien définie.
La fonction accepte deux arguments, dans l'ordre suivant:
- Une base de calcul de la taille, qui peut être un
<intrinsic-size-keyword>
, mais aussi uncalc-size()
imbriqué. - Un calcul calc-size, qui vous permet d'effectuer des calculs en utilisant la base calc-size. Pour faire référence à la base de calcul de la taille, utilisez le mot clé
size
.
Voici quelques exemples :
width: calc-size(auto, size); // = the auto width, unaltered
width: calc-size(min-content, size); // = the min-content width, unaltered
En ajoutant calc-size()
à la démonstration d'origine, le code se présente comme suit:
nav a {
width: 80px;
overflow-x: clip;
transition: width 0.35s ease;
&:hover,
&:focus-visible {
width: calc-size(max-content, size); /* 👈 */
}
}
Visuellement, le résultat est exactement le même que lorsque vous utilisez interpolate-size
. Dans ce cas précis, vous devez utiliser interpolate-size
.
calc-size()
se distingue par sa capacité à effectuer des calculs, ce qui est impossible avec interpolate-size
:
width: calc-size(auto, size - 10px); // = The auto width minus 10 pixels
width: calc-size(min-content, size + 1rem); // = The min-content width plus 1rem
width: calc-size(max-content, size * .5); // = Half the max-content width
Par exemple, si vous souhaitez que tous les paragraphes d'une page soient dimensionnés au multiple le plus proche de 50px
, vous pouvez utiliser la formule suivante:
p {
width: calc-size(fit-content, round(up, size, 50px));
height: calc-size(auto, round(up, size, 50px));
}
calc-size()
vous permet également d'interpoler entre deux calc-size()
lorsque leurs bases de taille de calcul sont identiques. Cela ne peut pas non plus être réalisé avec interpolate-size
.
#element {
width: min-content; /* 👈 */
transition: width 0.35s ease;
&:hover {
width: calc-size(min-content, size + 10px); /* 👈 */
}
}
Pourquoi ne pas autoriser <intrinsic-size-keyword>
dans calc()
?
Une question qui revient souvent avec calc-size()
est pourquoi le groupe de travail CSS n'a pas ajusté la fonction calc()
pour prendre en charge les mots clés de dimensionnement intrinsèque.
En effet, vous n'êtes pas autorisé à combiner des mots clés de dimensionnement intrinsèque lorsque vous effectuez des calculs. Par exemple, vous pourriez être tenté d'écrire calc(max-content - min-content)
, qui semble valide, mais qui ne l'est pas. calc-size()
applique la correction, car contrairement à calc()
, il n'accepte qu'un seul <intrinsic-size-keyword>
comme premier argument.
Une autre raison est la prise en compte du contexte. Certains algorithmes de mise en page ont un comportement spécial pour certains mots clés de dimensionnement intrinsèque. calc-size()
est défini explicitement pour représenter une taille intrinsèque, et non un <length>
. Grâce à cela, ces algorithmes peuvent traiter calc-size(<intrinsic-size-keyword>, …)
comme <intrinsic-size-keyword>
, tout en conservant son comportement spécial pour ce mot clé.
Quelle approche adopter ?
Dans la plupart des cas, déclarez interpolate-size: allow-keywords
sur :root
. Il s'agit du moyen le plus simple d'activer l'animation vers et depuis les mots clés de dimensionnement intrinsèque, car il s'agit essentiellement d'une ligne.
/* Opt-in the whole page to animating to/from intrinsic sizing keywords */
:root {
interpolate-size: allow-keywords; /* 👈 */
}
Ce morceau de code est une amélioration progressive intéressante, car les navigateurs qui ne le prennent pas en charge n'utilisent aucune transition.
Lorsque vous avez besoin d'un contrôle plus précis sur des éléments (par exemple, effectuer des calculs) ou que vous souhaitez utiliser un comportement que seul calc-size()
peut effectuer, vous pouvez utiliser calc-size()
.
#specific-element {
width: 50px;
&:hover {
width: calc-size(fit-content, size + 1em); /* 👈 Only calc-size() can do this */
}
}
Toutefois, si vous utilisez calc-size()
dans votre code, vous devrez inclure des solutions de remplacement pour les navigateurs qui ne sont pas compatibles avec calc-size()
. Par exemple, en ajoutant des déclarations de taille supplémentaires ou en revenant à la détection de fonctionnalités à l'aide de @supports
.
width: fit-content;
width: calc-size(fit-content, size + 1em);
/* 👆 Browsers with no calc-size() support will ignore this second declaration,
and therefore fall back to the one on the line before it. */
Autres démonstrations
Voici d'autres démonstrations qui exploitent interpolate-size: allow-keywords
à leur avantage.
Notifications
La démonstration suivante est un fork de cette démonstration @starting-style
. Le code a été ajusté pour permettre d'ajouter des éléments de différentes hauteurs.
Pour ce faire, l'interpolation de la taille des mots clés est activée pour l'ensemble de la page, et la valeur auto
est définie pour height
sur chaque élément .item
. Sinon, le code est exactement le même qu'avant le forking.
:root {
interpolate-size: allow-keywords; /* 👈 */
}
.item {
height: auto; /* 👈 */
@starting-style {
height: 0px;
}
}
Animer l'élément <details>
Un cas d'utilisation typique où vous pouvez utiliser ce type d'interpolation est d'animer un widget de divulgation ou un accordéon exclusif lorsqu'il s'ouvre. En HTML, vous utilisez l'élément <details>
pour ce faire.
Avec interpolate-size: allow-keywords
, vous pouvez aller très loin:
@supports (interpolate-size: allow-keywords) {
:root {
interpolate-size: allow-keywords;
}
details {
transition: height 0.5s ease;
height: 2.5rem;
&[open] {
height: auto;
overflow: clip; /* Clip off contents while animating */
}
}
}
Toutefois, comme vous pouvez le constater, l'animation ne s'exécute que lorsque le widget de divulgation s'ouvre. Pour y remédier, Chrome travaille sur le pseudo ::details-content
, qui sera disponible dans Chrome plus tard cette année (et qui sera abordé dans un prochain article). En combinant interpolate-size: allow-keywords
et ::details-content
, vous pouvez obtenir une animation dans les deux sens: