Blog / CSS & Interactions

Animation cadeau « unwrap » : séquencer avec transition-delay (CSS/JS)

Un cadeau qui fait un tour sur lui-même, dont le couvercle se soulève et d'où sort un code promo, avec étincelles — et qui se referme dans l'ordre inverse. Le tout en CSS/JS vanilla, grâce au séquençage par transition-delay.

Déballer un cadeau, c'est une séquence : la boîte tourne, le couvercle se soulève, le contenu apparaît. Reproduire ça proprement sur le web pose une vraie question — comment enchaîner plusieurs animations dans le bon ordre, et même les inverser à la fermeture, sans une usine à gaz de setTimeout ? Cet article décrit l'effet Gift Unwrap Reveal, l'effet gratuit du sprint Noël de décembre 2026 sur Effect.Labs, en CSS + JavaScript vanilla, accessible.

L'idée clé. On ne pilote pas le timing en JavaScript. On bascule une seule classe (.guw-open) et c'est transition-delay, élément par élément, qui orchestre la séquence — y compris un ordre différent à la fermeture.

La structure

Quatre pièces empilées, plus un wrapper qui tourne : le contenu (caché derrière la boîte), le corps de la boîte, le couvercle, le nœud.

<button class="guw-gift">
  <span class="guw-inner">            <!-- wrapper qui fait le tour 360° -->
    <span class="guw-code">🎄 NOEL30</span>  <!-- z sous la boîte : caché -->
    <span class="guw-box"></span>       <!-- corps (couvre le code) -->
    <span class="guw-lid"></span>       <!-- couvercle -->
    <span class="guw-bow">🎀</span>
  </span>
</button>

Le tour sur soi-même (360°)

Le wrapper .guw-inner tourne d'un tour complet. Comme 360° = orientation de départ, la boîte revient à sa place : un twirl satisfaisant et toujours face à l'utilisateur.

.guw-inner { transition: transform .75s cubic-bezier(.45,.05,.2,1); }
.guw-open .guw-inner { transform: rotate(360deg); }

Séquencer avec transition-delay

Chaque pièce a un délai croissant : la boîte tourne (0), puis le couvercle se soulève (.78s), puis le code sort (1s). Un seul changement de classe, zéro setTimeout.

.guw-open .guw-inner { transform: rotate(360deg);                 transition-delay: 0s;   }
.guw-open .guw-lid   { transform: translateY(-86px) rotate(-10deg); transition-delay: .78s; }
.guw-open .guw-code  { transform: translateY(-104px) scale(1);      transition-delay: 1s;   }

L'astuce : un ordre inversé à la fermeture

À la fermeture, on veut l'inverse : le code rentre d'abord, puis le couvercle se referme. La clé : une transition lit son délai dans l'état CIBLE. On met donc les délais d'ouverture sur .guw-open, et les délais de fermeture (inversés) sur l'état de base.

/* état de base = ce qui s'applique à la FERMETURE */
.guw-code { transition: transform .55s ...; transition-delay: 0s;   } /* le code rentre en 1er */
.guw-lid  { transition: transform .5s  ...; transition-delay: .55s; } /* couvercle après */
.guw-inner{ transition: transform .75s ...; transition-delay: .9s;  } /* tour de retour en dernier */

Résultat : ouverture = tour → couvercle → code ; fermeture = code → couvercle → tour. Le code complet est disponible sur la page Hover du cataloguecet effet est gratuit.

Cacher puis révéler le contenu (z-index)

Le code promo est placé derrière le corps de la boîte (z-index inférieur), dans le même contexte d'empilement. Tant qu'il est dans la zone de la boîte, il est occulté ; quand il remonte au-dessus du bord supérieur, il devient visible — sans aucun fondu d'opacité.

Étincelles & accessibilité

À l'ouverture, on génère une douzaine de petites étincelles en burst (de simples <span> animés, auto-nettoyés). Côté accessibilité :

  • Un vrai <button> : ouverture au clavier (Entrée/Espace), annoncé par les lecteurs d'écran.
  • prefers-reduced-motion : on saute le spin, l'envol et les étincelles — le contenu est révélé directement.

Ce que ChatGPT et v0 ne font pas

Demandez une « animation cadeau » à un générateur : vous obtenez souvent un empilement de setTimeout fragile, et jamais l'ordre inversé à la fermeture. Ce qui est rarement maîtrisé :

  • Le séquençage par transition-delay (au lieu de timers JS) — robuste et déclaratif.
  • Les délais asymétriques ouverture/fermeture (lecture du délai dans l'état cible) : presque jamais proposé.
  • L'occlusion par z-index dans le même contexte d'empilement pour cacher/révéler sans fondu.
  • prefers-reduced-motion et le nettoyage des particules : souvent oubliés.

Questions fréquentes

Peut-on l'utiliser avec React, Vue ou Svelte ?

Oui : CSS + JavaScript vanilla, aucune dépendance npm. Dans React, gérer l'état ouvert/fermé avec useState et basculer une classe ; le séquençage reste 100% CSS.

Comment changer le contenu révélé ?

Le contenu est un simple élément (ici un code promo) ; remplacez-le par un message, un bon d'achat, un visuel… L'animation est agnostique du contenu, piloté par data-code.

Le code complet, prêt à l'emploi

Cet effet est gratuit ce mois-ci. Copiez-collez le code et adaptez le contenu révélé. Accès à 800+ autres effets premium avec l'abonnement.

Rejoindre les fondateurs — 9,90 € / mois