Comment animer display: none sans recourir à JavaScript
Animez display none en CSS avec allow-discrete et @starting-style, plus la gestion overlay des dialogs et popovers et la prise en charge navigateur.
Pour animer un élément vers ou depuis display: none en CSS pur, ajoutez display à votre transition avec le mot-clé allow-discrete et fournissez l’état d’entrée dans une règle @starting-style — sans JavaScript, sans setTimeout, sans écouteur transitionend. Deux fonctionnalités ont été introduites pour rendre cela possible : transition-behavior: allow-discrete permet aux propriétés discrètes comme display de participer à une transition, et @starting-style fournit au navigateur un état « avant ouverture » depuis lequel animer l’entrée. Ce guide vous propose des recettes d’entrée et de sortie prêtes à l’emploi, le cas particulier des dialog/popover dans la couche supérieure avec son écueil lié à overlay, ainsi qu’un état honnête de la prise en charge actuelle par les navigateurs.
Points clés à retenir
- Animez
displayen l’incluant dans le raccourcitransitionavecallow-discrete, et définissez l’état d’entrée dans un bloc@starting-style— aucun JavaScript n’est requis. displayest une propriété discrète : avecallow-discrete, le navigateur la bascule vers la valeur visible à 0 % à l’entrée et versnoneà 100 % à la sortie, de sorte que le contenu reste visible pendant toute la durée de la transition.- Si vous utilisez la propriété autonome
transition-behavior: allow-discrete, elle doit être déclarée après le raccourcitransition, sinon le navigateur l’ignore. - Pour les dialogues et les popovers, pensez également à faire transitionner
overlay ... allow-discrete, mais traitez-le comme une amélioration progressive, caroverlayn’est pas encore dans la Baseline. @starting-styleetallow-discretefont partie de la Baseline Newly available depuis la sortie de Firefox 129 le 6 août 2024 ; en l’absence de prise en charge, l’élément apparaît et disparaît simplement de façon instantanée.
Pourquoi display: none ne pouvait pas être transitionné
Une transition CSS a besoin d’un style avant changement depuis lequel animer. Un élément avec display: none — ou un élément qui vient d’être inséré dans le DOM — ne possède aucun état rendu précédent, si bien que le navigateur n’avait historiquement rien sur quoi interpoler et la transition ne se déclenchait jamais. C’est pourquoi les développeurs avaient recours à des manipulations de classes via setTimeout ou à des hacks de reflow avec un double requestAnimationFrame.
Le raccourci courant — effectuer un fondu avec opacity: 0 tout en laissant l’élément dans le DOM — n’est pas un substitut valable. opacity: 0 laisse l’élément dans la mise en page, dans l’ordre de tabulation et dans l’arbre d’accessibilité, si bien que les utilisateurs au clavier et les lecteurs d’écran peuvent toujours atteindre un contenu qui semble avoir disparu. display: none le retire des trois. En pratique, les replays de session sur des composants partiellement migrés font remonter exactement ce type de bogue : un utilisateur qui navigue au clavier ou clique dans un panneau qui paraît fermé, mais qui n’a été que fondu et jamais retiré de la mise en page. Animer un vrai display: none élimine ce problème.
Discover how at OpenReplay.com.
Les deux fonctionnalités CSS qui résolvent le problème : allow-discrete et @starting-style
display est une propriété discrète — elle ne peut pas interpoler entre des valeurs, c’est un interrupteur tout ou rien. Les propriétés animées de façon discrète basculent généralement entre deux valeurs à 50 % de l’animation ; l’exception concerne les animations vers ou depuis display: none ou content-visibility: hidden, auquel cas le navigateur effectue la bascule de façon à ce que le contenu transitionné soit visible pendant toute la durée de l’animation. La direction est importante : lors de l’animation de display de none vers block, la valeur bascule vers block à 0 % de la durée afin d’être visible tout au long de la transition ; lors de l’animation de block vers none, elle bascule vers none à 100 % de la durée afin de rester visible jusqu’au bout — ce qui est ce qui maintient le fondu réellement visible dans les deux sens.
Vous activez ce comportement en définissant transition-behavior: allow-discrete sur la transition de display, et vous fournissez l’état d’entrée avec @starting-style.
La recette de sortie : transition vers display: none
Pour faire disparaître un élément en fondu puis le retirer de la mise en page, incluez display dans la transition avec allow-discrete et définissez l’état masqué :
.panel {
opacity: 1;
transition: opacity 0.3s ease, display 0.3s allow-discrete;
}
.panel.is-hidden {
opacity: 0;
display: none;
}
L’opacité s’anime vers 0 sur 300 ms ; display maintient sa valeur visible jusqu’à 100 %, puis bascule vers none. Si vous oubliez allow-discrete sur display, l’élément disparaît instantanément — c’est l’erreur la plus fréquente avec cette technique.
La recette d’entrée : animer depuis display: none
Pour un élément qui commence masqué, placez les valeurs « avant ouverture » dans une règle @starting-style. Avec l’imbrication CSS, l’ensemble tient en un seul bloc :
.panel {
display: none;
opacity: 0;
transition: opacity 0.3s ease, display 0.3s allow-discrete;
}
.panel.is-open {
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
L’ordre est important. @starting-style possède la même spécificité que la règle qu’il cible, il doit donc être placé après la déclaration de l’état ouvert pour l’emporter dans la cascade. Il existe également un piège en une ligne : si vous appliquez transition-behavior: allow-discrete avant le raccourci transition, le navigateur ignorera le transition-behavior. Lorsqu’il est écrit de façon autonome, il doit être placé en dernier :
.panel {
transition: opacity 0.3s, display 0.3s;
transition-behavior: allow-discrete; /* doit venir APRÈS le raccourci */
}
Pour les moteurs plus anciens, le modèle multi-navigateurs de MDN déclare transition deux fois — la première instance, sans allow-discrete, assure la compatibilité multi-navigateurs, garantissant que les autres propriétés continuent de transitionner dans les navigateurs qui ne prennent pas en charge transition-behavior.
Dialogues et popovers : l’écueil d’overlay
Les éléments de la couche supérieure — <dialog> et tout élément utilisant l’attribut popover — représentent le cas d’usage le plus intéressant, et ils comportent une exigence supplémentaire. Pour les dialogues et les popovers, vous devez également faire transitionner overlay ... allow-discrete, sinon l’élément quitte instantanément la couche supérieure et l’animation de sortie ne s’affiche jamais :
dialog {
translate: 0 100vh;
transition:
translate 0.4s ease-out,
display 0.4s allow-discrete,
overlay 0.4s allow-discrete;
}
dialog[open] {
translate: 0 0;
@starting-style {
translate: 0 100vh;
}
}
Pour un popover, remplacez dialog[open] par la pseudo-classe :popover-open. La propriété overlay est ce qui diffère le retrait de la couche supérieure : elle garantit que la suppression de l’élément de la couche supérieure est reportée jusqu’à la fin de l’animation ; dans des cas plus complexes, ne pas le faire peut entraîner la suppression prématurée de l’élément de la couche de superposition, rendant l’animation saccadée ou inefficace.
Une mise en garde honnête que d’autres passent sous silence : overlay ne fait pas partie de la Baseline. MDN le marque comme expérimental — cette fonctionnalité ne fait pas partie de la Baseline car elle ne fonctionne pas dans certains des navigateurs les plus utilisés. Traitez-la comme une amélioration progressive ; là où elle n’est pas prise en charge, le dialogue s’ouvre et se ferme tout de même, simplement sans la sortie différée.
Prise en charge par les navigateurs et dégradation gracieuse
@starting-style et transition-behavior: allow-discrete sont tous deux devenus Baseline Newly available avec Firefox 129, sorti le 6 août 2024. Mais animer display lui-même nécessite plus que ces deux fonctionnalités. Cela fonctionne dans Chrome et Edge 117+ ainsi que dans Safari 18+ — Safari 17.4 a ajouté transition-behavior et 17.5 a ajouté @starting-style, mais la transition de display avec ces fonctionnalités ne fonctionne qu’à partir de Safari 18. Firefox 129+ prend en charge les deux fonctionnalités, mais à mi-2026, il ne fait toujours pas transitionner la propriété display, de sorte que dans Firefox l’élément s’affiche et se masque instantanément. display dans @keyframes fonctionne depuis Chrome 116.
| Fonctionnalité | Statut | Comportement de repli |
|---|---|---|
transition-behavior: allow-discrete | Baseline (août 2024) | Affichage/masquage instantané |
@starting-style | Baseline (août 2024) | Pas d’animation d’entrée |
overlay | Pas dans la Baseline | Le dialogue s’ouvre/se ferme quand même |
Il s’agit d’une amélioration progressive pure. En l’absence de ces fonctionnalités, les éléments animés vers la couche supérieure ou depuis un style display: none apparaîtront simplement sur la page sans transition, comme c’est le cas aujourd’hui. Aucun polyfill, aucun fallback JavaScript n’est nécessaire. Conditionnez l’amélioration avec une détection de fonctionnalité si vous souhaitez une délimitation explicite :
@supports (transition-behavior: allow-discrete) {
/* animations d'entrée/sortie modernes */
}
Quand privilégier les View Transitions
Utilisez ces transitions lorsque vous basculez la visibilité d’un élément existant. Optez plutôt pour l’API View Transitions lorsque vous ajoutez ou supprimez des nœuds du DOM. Les transitions de vue dans le même document sont Baseline Newly available depuis le 14 octobre 2025, suite à la sortie de Firefox 144 le même jour — prise en charge dans Chrome 111+, Edge 111+, Safari 18+ et Firefox 144+. Encapsulez la mutation du DOM dans document.startViewTransition() avec un fallback simple :
if (document.startViewTransition) {
document.startViewTransition(() => card.remove());
} else {
card.remove();
}
La recette moderne met fin à l’ancienne orchestration JavaScript : incluez display dans votre transition avec allow-discrete, définissez l’état d’entrée dans @starting-style, ajoutez overlay pour les éléments de la couche supérieure, et laissez les navigateurs non compatibles revenir à un affichage instantané. Abandonnez le setTimeout et livrez du CSS.
FAQ
Pourquoi mon animation de sortie ne se déclenche-t-elle pas même après avoir ajouté allow-discrete à la transition de display ?
La cause la plus fréquente est que la déclaration autonome transition-behavior: allow-discrete est placée avant le raccourci transition, ce qui amène le navigateur à l'ignorer silencieusement. Lorsqu'elle est écrite comme propriété séparée, transition-behavior doit apparaître après le raccourci transition, sinon ce dernier la réinitialise. Si vous intégrez allow-discrete directement dans la valeur de transition, l'ordre au sein du raccourci n'a pas d'importance et ce piège ne s'applique pas.
Ai-je encore besoin de @starting-style si je veux uniquement faire disparaître un élément en fondu vers display: none ?
Non. @starting-style n'est requis que pour les animations d'entrée, lorsque l'élément passe de display: none ou vient d'être inséré dans le DOM et a besoin d'un état avant ouverture depuis lequel animer. Une sortie pure — animer un élément déjà visible vers display: none — nécessite uniquement que display soit inclus dans la transition avec allow-discrete et que l'état masqué soit défini. N'ajoutez @starting-style que si vous animez également l'entrée de l'élément.
Que se passe-t-il dans les navigateurs qui ne prennent pas en charge transition-behavior ou @starting-style ?
L'élément apparaît et disparaît simplement de façon instantanée, exactement comme sans aucune animation. Il s'agit d'une amélioration progressive, donc aucun polyfill ni fallback JavaScript n'est nécessaire. Pour les dialogues et les popovers, les navigateurs ne prenant pas en charge la propriété overlay — qui n'est pas dans la Baseline — ouvrent et ferment tout de même l'élément correctement ; ils sautent simplement la sortie différée de la couche supérieure. Vous pouvez conditionner l'amélioration explicitement avec une règle @supports (transition-behavior: allow-discrete).
Quand dois-je utiliser l'API View Transitions plutôt qu'animer display: none ?
Utilisez View Transitions lorsque vous ajoutez ou supprimez des nœuds du DOM, et utilisez les transitions de display lorsque vous basculez la visibilité d'un élément qui existe déjà dans le DOM. Les transitions de vue dans le même document sont devenues Baseline Newly available le 14 octobre 2025, prises en charge dans Chrome 111+, Edge 111+, Safari 18+ et Firefox 144+. Encapsulez la mutation du DOM dans document.startViewTransition() avec un fallback simple pour les moteurs non compatibles.