Cette page a été traduite à partir de l'anglais par la communauté. Vous pouvez contribuer en rejoignant la communauté francophone sur MDN Web Docs.

View in English Always switch to English

@starting-style

Baseline 2024
Newly available

Since ⁨August 2024⁩, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

La règle @ CSS @starting-style est utilisée pour définir les valeurs de départ des propriétés appliquées à un élément, à partir desquelles vous souhaitez effectuer une transition lors de la première mise à jour de style de l'élément, c'est-à-dire lorsqu'un élément est affiché pour la première fois sur une page déjà chargée.

Syntaxe

La règle @starting-style peut être utilisée de deux façons :

  1. Comme bloc autonome, auquel cas elle contient un ou plusieurs ensembles de règles définissant les déclarations de style de départ et sélectionnant les éléments auxquels elles s'appliquent :

    css
    @starting-style {
      /* règles */
    }
    
  2. Imbriquée dans un ensemble de règles existant, auquel cas elle contient une ou plusieurs déclarations définissant les valeurs de départ des propriétés pour les éléments déjà sélectionnés par cet ensemble de règles :

    css
    selector {
      /* règles existantes */
      /* ... */
    
      @starting-style {
        /* déclarations */
      }
    }
    

Description

Pour éviter un comportement inattendu, les transitions CSS ne sont pas déclenchées par défaut lors de la première mise à jour de style d'un élément, ou lorsque son type display passe de none à une autre valeur. Pour activer les transitions sur le premier style, il faut utiliser des règles starting-style. Elles fournissent des styles de départ pour les éléments qui n'ont pas d'état précédent, en définissant les valeurs de propriété à partir desquelles effectuer la transition.

@starting-style est particulièrement utile pour créer des transitions d'entrée et de sortie pour les éléments affichés dans la couche supérieure (comme les popovers et les boîtes de dialogue modales <dialog>), les éléments qui changent vers ou depuis display: none, et les éléments ajoutés ou retirés du DOM pour la première fois.

Note : @starting-style ne concerne que les transitions CSS. Lorsque vous utilisez des animations CSS pour réaliser de tels effets, @starting-style n'est pas nécessaire. Voir Utiliser les animations CSS pour un exemple.

Il existe deux façons d'utiliser @starting-style : comme règle autonome ou imbriquée dans un ensemble de règles.

Prenons le cas où vous souhaitez animer un popover lorsqu'il est affiché (c'est-à-dire lorsqu'il est ajouté à la top layer). La « règle originale » qui définit les styles du popover ouvert pourrait ressembler à ceci (voir l'exemple de popover ci-dessous) :

css
[popover]:popover-open {
  opacity: 1;
  transform: scaleX(1);
}

Pour spécifier les valeurs de départ des propriétés du popover à animer avec la première méthode, vous incluez un bloc autonome @starting-style dans votre CSS :

css
@starting-style {
  [popover]:popover-open {
    opacity: 0;
    transform: scaleX(0);
  }
}

Note : La règle @starting-style et la « règle originale » ont la même spécificité. Pour garantir l'application des styles de départ, placez la règle @starting-style après la « règle originale ». Si vous la placez avant, les styles originaux écraseront les styles de départ.

Pour spécifier le style de départ du popover avec la méthode imbriquée, vous pouvez imbriquer le bloc @starting-style dans la « règle originale » :

css
[popover]:popover-open {
  opacity: 1;
  transform: scaleX(1);

  @starting-style {
    opacity: 0;
    transform: scaleX(0);
  }
}

Quand les styles de départ sont-ils utilisés ?

Il est important de comprendre qu'un élément va effectuer une transition à partir de ses styles @starting-style lorsqu'il est rendu pour la première fois dans le DOM, ou lorsqu'il passe de display: none à une valeur visible. Lorsqu'il repasse de son état visible initial, il n'utilisera plus les styles @starting-style car il est désormais visible dans le DOM. Il effectuera alors une transition vers les styles définis pour l'état par défaut de l'élément.

En pratique, il y a trois états de style à gérer dans ces situations : l'état de départ (@starting-style), l'état transitionné, et l'état par défaut. Il est possible que les transitions « vers » et « depuis » soient différentes dans ces cas. Vous pouvez voir une démonstration dans notre Exemple de quand les styles de départ sont utilisés ci-dessous.

Syntaxe formelle

@starting-style = 
@starting-style { <rule-list> }

Exemples

Utilisation basique de @starting-style

Faites passer la background-color d'un élément de transparent à vert lors de son rendu initial :

css
#target {
  transition: background-color 1.5s;
  background-color: green;
}

@starting-style {
  #target {
    background-color: transparent;
  }
}

Faites passer la opacity d'un élément lorsqu'il change sa valeur display vers ou depuis none :

css
#target {
  transition-property: opacity, display;
  transition-duration: 0.5s;
  display: block;
  opacity: 1;
  @starting-style {
    opacity: 0;
  }
}

#target.hidden {
  display: none;
  opacity: 0;
}

Démonstration de l'utilisation des styles de départ

Dans cet exemple, un bouton est pressé pour créer un élément <div>, lui donner la classe showing, et l'ajouter au DOM.

La classe showing reçoit un style de départ @starting-style de background-color: red et un style de transition vers background-color: blue. Le bloc de règles par défaut du div contient background-color: yellow, et c'est aussi là que la propriété transition est définie.

Lorsque le <div> est ajouté au DOM pour la première fois, le fond passe de rouge à bleu. Après un délai, la classe showing est retirée du <div> via JavaScript. À ce moment-là, la transition se fait de bleu vers jaune, et non vers rouge. Cela prouve que les styles de départ ne sont utilisés que lors du premier rendu de l'élément dans le DOM. Une fois affiché, l'élément revient au style par défaut qui lui est appliqué.

Après un autre délai, le <div> est retiré du DOM, réinitialisant l'état initial de l'exemple pour pouvoir le relancer.

HTML

html
<button>Afficher <code>&lt;div&gt;</code></button>

CSS

css
div {
  background-color: yellow;
  transition: background-color 3s;
}

div.showing {
  background-color: skyblue;
}

@starting-style {
  div.showing {
    background-color: red;
  }
}

JavaScript

js
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  btn.disabled = true;
  const divElem = document.createElement("div");
  divElem.classList.add("showing");
  document.body.append(divElem);

  setTimeout(() => {
    divElem.classList.remove("showing");

    setTimeout(() => {
      divElem.remove();
      btn.disabled = false;
    }, 3000);
  }, 3000);
});

Résultat

Le code s'affiche ainsi :

Animation d'un popover

Dans cet exemple, un popover est animé à l'aide des transitions CSS. Des animations d'entrée et de sortie basiques sont fournies via la propriété transition.

HTML

Le HTML contient un élément <div> déclaré comme popover grâce à l'attribut popover et un élément <button> servant de contrôle d'affichage du popover via son attribut popovertarget.

html
<button popovertarget="mypopover">Afficher le popover</button>
<div popover="auto" id="mypopover">
  Je suis un popover&nbsp;! Je devrais être animé.
</div>

CSS

Dans cet exemple, on souhaite animer deux propriétés, opacity et transform (notamment une transformation d'échelle horizontale), pour faire apparaître/disparaître le popover et le faire grandir/rétrécir horizontalement.

css
html {
  font-family: Arial, Helvetica, sans-serif;
}

[popover]:popover-open {
  opacity: 1;
  transform: scaleX(1);
}

[popover] {
  font-size: 1.2rem;
  padding: 10px;

  /* État final de l'animation de sortie */
  opacity: 0;
  transform: scaleX(0);

  transition:
    opacity 0.7s,
    transform 0.7s,
    overlay 0.7s allow-discrete,
    display 0.7s allow-discrete;
  /* Équivalent à
  transition: all 0.7s allow-discrete; */
}

/* À inclure après la règle [popover]:popover-open */
@starting-style {
  [popover]:popover-open {
    opacity: 0;
    transform: scaleX(0);
  }
}

/* Transition pour le backdrop du popover */
[popover]::backdrop {
  background-color: transparent;
  transition:
    display 0.7s allow-discrete,
    overlay 0.7s allow-discrete,
    background-color 0.7s;
  /* Équivalent à
  transition: all 0.7s allow-discrete; */
}

[popover]:popover-open::backdrop {
  background-color: rgb(0 0 0 / 25%);
}

/* L'imbrication (&) n'est pas supportée pour les pseudo-éléments,
il faut donc spécifier un bloc autonome starting-style. */
@starting-style {
  [popover]:popover-open::backdrop {
    background-color: transparent;
  }
}

Pour cela, on définit un état de départ pour ces propriétés sur l'état caché par défaut de l'élément popover (sélectionné via [popover]), et un état final sur l'état ouvert du popover (sélectionné via la pseudo-classe :popover-open).

On définit ensuite la propriété transition pour animer entre les deux états. Un état de départ pour l'animation est inclus dans une règle @starting-style pour activer l'animation d'entrée.

Comme l'élément animé est promu dans la couche supérieure, lorsqu'il est affiché et retiré de la couche supérieure et lorsqu'il est caché (avec display: none), quelques étapes supplémentaires sont nécessaires pour garantir que l'animation fonctionne dans les deux sens :

  • display est ajouté à la liste des propriétés animées pour garantir que l'élément animé reste visible (défini sur display: block ou une autre valeur visible) pendant toute l'animation d'entrée et de sortie. Sans cela, l'animation de sortie ne serait pas visible : le popover disparaîtrait simplement. Notez que la valeur transition-behavior: allow-discrete est aussi définie dans le raccourci pour activer l'animation.
  • overlay est ajouté à la liste des propriétés animées pour garantir que le retrait de l'élément de la couche supérieure soit différé jusqu'à la fin de l'animation. Cela n'a pas un grand impact pour ce type d'animation, mais dans des cas plus complexes, ne pas le faire peut entraîner le retrait trop rapide de l'élément, rendant l'animation peu fluide ou inefficace. Là encore, transition-behavior: allow-discrete est requis pour que l'animation ait lieu.

Note : Une transition est aussi appliquée au ::backdrop qui apparaît derrière le popover à l'ouverture, pour une animation d'assombrissement agréable. [popover]:popover-open::backdrop est utilisé pour cibler le backdrop lorsque le popover est ouvert.

Résultat

Le code s'affiche ainsi :

Note : Comme les popovers passent de display: none à display: block à chaque affichage, le popover effectue une transition de ses styles @starting-style vers ses styles [popover]:popover-open à chaque animation d'entrée. Lorsqu'il se ferme, il passe de l'état [popover]:popover-open à l'état [popover] par défaut.

Note : Vous trouverez un exemple montrant la transition d'un élément <dialog> et de son backdrop lors de l'affichage et de la fermeture sur la page de référence <dialog> — voir Transition des éléments dialog.

Transition d'éléments lors de l'ajout et du retrait dans le DOM

Cet exemple contient un bouton qui, lorsqu'il est pressé, ajoute de nouveaux éléments à un conteneur <section>. Chaque élément contient à son tour un bouton imbriqué qui, lorsqu'il est pressé, retire l'élément. Cet exemple montre comment utiliser les transitions pour animer les éléments lors de leur ajout ou retrait du DOM.

HTML

html
<button>Créer une nouvelle colonne</button>
<section></section>

JavaScript

Le JavaScript permet l'ajout et le retrait des éléments :

js
const btn = document.querySelector("button");
const sectionElem = document.querySelector("section");

btn.addEventListener("click", createColumn);

function randomBackground() {
  function randomNum() {
    return Math.floor(Math.random() * 255);
  }
  const baseColor = `${randomNum()} ${randomNum()} ${randomNum()}`;

  return `linear-gradient(to right, rgb(${baseColor} / 0), rgb(${baseColor} / 0.5))`;
}

function createColumn() {
  const divElem = document.createElement("div");
  divElem.style.background = randomBackground();

  const closeBtn = document.createElement("button");
  closeBtn.textContent = "✖";
  closeBtn.setAttribute("aria-label", "fermer");
  divElem.append(closeBtn);
  sectionElem.append(divElem);

  closeBtn.addEventListener("click", () => {
    divElem.classList.add("fade-out");

    setTimeout(() => {
      divElem.remove();
    }, 1000);
  });
}

Lorsque le bouton « Créer une nouvelle colonne » est cliqué, la fonction createColumn() est appelée. Elle crée un élément <div> avec une couleur de fond générée aléatoirement et un bouton <button> pour fermer le <div>. Le bouton est ajouté au <div>, puis le <div> au conteneur <section>.

On ajoute ensuite un écouteur d'événement au bouton de fermeture via addEventListener(). Cliquer sur le bouton fait deux choses :

  • Ajoute la classe fade-out au <div>. L'ajout de la classe déclenche l'animation de sortie définie sur cette classe.
  • Retire le <div> après un délai de 1000 ms. La fonction setTimeout() retarde le retrait du <div> du DOM (via Element.remove()) jusqu'à la fin de l'animation.

CSS

On inclut une propriété transition qui anime la opacity et la scale de chaque colonne lors de leur ajout et retrait :

css
div {
  flex: 1;
  border: 1px solid gray;
  position: relative;
  opacity: 1;
  scale: 1 1;

  transition:
    opacity 0.7s,
    scale 0.7s,
    display 0.7s allow-discrete,
    all 0.7s allow-discrete;
  /* Équivalent à
  transition: all 0.7s allow-discrete; */
}

/* À inclure après la règle `div` */
@starting-style {
  div {
    opacity: 0;
    scale: 1 0;
  }
}

.fade-out {
  opacity: 0;
  display: none;
  scale: 1 0;
}

div > button {
  font-size: 1.6rem;
  background: none;
  border: 0;
  text-shadow: 2px 1px 1px white;
  border-radius: 15px;
  position: absolute;
  top: 1px;
  right: 1px;
  cursor: pointer;
}

Pour animer la opacity et la scale de chaque <div> lors de son ajout au DOM puis inverser l'animation lors de son retrait, on :

  • Définit l'état final des propriétés à animer dans la règle div { ... }.
  • Définit l'état de départ à partir duquel effectuer la transition dans un bloc @starting-style.
  • Définit l'animation de sortie dans la règle .fade-out — c'est la classe que le JavaScript assigne aux éléments <div> lorsque leur bouton de fermeture est pressé. En plus de définir les états finaux d'opacity et scale, on définit aussi display: none sur les <div> — on souhaite qu'ils deviennent immédiatement indisponibles une fois retirés de l'interface.
  • Définit la liste transition dans la règle div { ... } pour animer opacity, scale et display. Notez que pour display, la valeur transition-behavior: allow-discrete est aussi définie dans le raccourci pour que l'animation ait lieu.

Résultat

Le résultat final ressemble à ceci :

Spécifications

Specification
CSS Transitions Level 2
# defining-before-change-style

Compatibilité des navigateurs

Voir aussi