ITSkillsCenter
Design & UX

Comment créer des transitions de page fluides

9 دقائق للقراءة

Pourquoi les transitions de page changent la perception de votre site

Sur un site web classique, chaque changement de page est brutal : écran blanc, rechargement complet, contenu qui apparaît d’un coup. Les utilisateurs perçoivent cette rupture comme de la lenteur, même si le chargement prend moins d’une seconde. Les transitions de page fluides éliminent cette discontinuité et donnent l’impression d’une application native plutôt qu’un site web.

Des études UX montrent qu’une transition bien conçue de 300-500ms réduit la perception du temps d’attente de 40%. Les sites d’agences, portfolios et e-commerce haut de gamme utilisent systématiquement ces techniques pour créer une expérience mémorable.

La View Transitions API : la révolution native du navigateur

Qu’est-ce que c’est ?

La View Transitions API est une fonctionnalité native des navigateurs (Chrome, Edge, Opera — support Safari en cours) qui permet de créer des transitions animées entre deux états de page sans bibliothèque externe. C’est la méthode recommandée en 2025 pour les transitions de page.

Transition simple entre pages (MPA)

Pour les sites multi-pages classiques (WordPress, sites statiques), ajoutez cette meta-tag dans le head :

/* Dans votre CSS */
@view-transition {
  navigation: auto;
}

/* Personnaliser l'animation par défaut */
::view-transition-old(root) {
  animation: fade-out 0.3s ease-in;
}

::view-transition-new(root) {
  animation: fade-in 0.3s ease-out;
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

C’est tout. Deux lignes de CSS (@view-transition et les animations) et votre site entier a des transitions fluides entre chaque page. Le navigateur capturé un « screenshot » de l’ancien état, navigue, puis anime vers le nouvel état.

Transitions ciblées sur des éléments spécifiques

Le vrai pouvoir vient du ciblage d’éléments individuels. Imaginez : cliquer sur une miniature de produit et la voir s’agrandir fluidement pour devenir l’image de la page produit.

/* Attribuez un nom de transition à un élément */
.product-image {
  view-transition-name: product-hero;
}

/* Sur la page de destination, le même nom */
.product-detail-image {
  view-transition-name: product-hero;
}

/* Le navigateur anime automatiquement entre les deux */
::view-transition-old(product-hero) {
  animation: none; /* On laisse le morphing automatique */
}

::view-transition-new(product-hero) {
  animation: none;
}

/* Pendant ce temps, le reste de la page fait un crossfade */
::view-transition-old(root) {
  animation: fade-and-slide-out 0.4s ease-in;
}

::view-transition-new(root) {
  animation: fade-and-slide-in 0.4s ease-out;
}

@keyframes fade-and-slide-out {
  to { opacity: 0; transform: translateY(-20px); }
}

@keyframes fade-and-slide-in {
  from { opacity: 0; transform: translateY(20px); }
}

Le navigateur calcule automatiquement la transformation (position, taille) entre les deux éléments portant le même view-transition-name. C’est l’équivalent du « shared élément transition » d’Android, mais en CSS natif.

Transitions avec JavaScript : contrôle total (SPA)

document.startViewTransition()

Pour les applications single-page (React, Vue, Next.js), vous déclenchez les transitions manuellement :

// Transition basique lors d'un changement de contenu
async function navigateTo(url) {
  // Vérifie si l'API est supportée
  if (!document.startViewTransition) {
    // Fallback : navigation classique
    updateContent(url);
    return;
  }

  const transition = document.startViewTransition(async () => {
    // Cette fonction met à jour le DOM
    await updateContent(url);
  });

  // Optionnel : attendre la fin de l'animation
  await transition.finished;
}

async function updateContent(url) {
  const response = await fetch(url);
  const html = await response.text();
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, 'text/html');
  
  // Remplace le contenu principal
  document.querySelector('main').innerHTML = 
    doc.querySelector('main').innerHTML;
  
  // Met à jour le titre
  document.title = doc.title;
  
  // Met à jour l'URL
  history.pushState({}, '', url);
}

Types de transition selon la direction

Ajoutez des classes pour différencier les transitions avant/arrière :

async function navigateTo(url, direction = 'forward') {
  if (!document.startViewTransition) {
    updateContent(url);
    return;
  }

  // Applique une classé pour la direction
  document.documentElement.dataset.transition = direction;

  const transition = document.startViewTransition(() => updateContent(url));
  await transition.finished;
  
  delete document.documentElement.dataset.transition;
}

/* CSS selon la direction */
[data-transition="forward"]::view-transition-old(root) {
  animation: slide-out-left 0.4s ease-in;
}
[data-transition="forward"]::view-transition-new(root) {
  animation: slide-in-right 0.4s ease-out;
}

[data-transition="back"]::view-transition-old(root) {
  animation: slide-out-right 0.4s ease-in;
}
[data-transition="back"]::view-transition-new(root) {
  animation: slide-in-left 0.4s ease-out;
}

@keyframes slide-out-left {
  to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in-right {
  from { transform: translateX(100%); opacity: 0; }
}
@keyframes slide-out-right {
  to { transform: translateX(100%); opacity: 0; }
}
@keyframes slide-in-left {
  from { transform: translateX(-100%); opacity: 0; }
}

5 patterns de transitions professionnelles

1. Le crossfade élégant

La transition la plus universelle. L’ancien contenu s’efface pendant que le nouveau apparaît. Subtile, professionnelle, adaptée à tous les types de sites.

::view-transition-old(root) {
  animation: 0.3s ease-out both fade-out;
}

::view-transition-new(root) {
  animation: 0.3s ease-in both fade-in;
  animation-delay: 0.1s; /* Léger décalage pour éviter le flash */
}

/* Durée totale perçue : ~400ms — le sweet spot */

2. Le slide vertical (scroll-like)

L’ancien contenu glisse vers le haut, le nouveau arrive par le bas. Donne une impression de continuité verticale, idéal pour les blogs et les sites de contenu long.

::view-transition-old(root) {
  animation: 0.4s cubic-bezier(0.4, 0, 0.2, 1) both slide-up-out;
  z-index: 1;
}

::view-transition-new(root) {
  animation: 0.4s cubic-bezier(0.4, 0, 0.2, 1) both slide-up-in;
  z-index: 2;
}

@keyframes slide-up-out {
  to { transform: translateY(-30px); opacity: 0; }
}

@keyframes slide-up-in {
  from { transform: translateY(60px); opacity: 0; }
}

3. Le morph de carte (e-commerce/portfolio)

L’élément cliqué (carte produit, image de portfolio) se transforme en contenu de la page de destination. La technique la plus impressionnante visuellement.

/* Page liste */
.card-image { view-transition-name: hero-image; }
.card-title { view-transition-name: hero-title; }

/* Page détail */
.detail-image { view-transition-name: hero-image; }
.detail-title { view-transition-name: hero-title; }

/* Important : un seul élément par nom sur chaque page */
/* Si vous avez une liste de cartes, assignez dynamiquement */

/* JavaScript pour assigner le nom uniquement à la carte cliquée */
document.querySelectorAll('.card').forEach(card => {
  card.addEventListener('click', (e) => {
    // Retire le nom des autres cartes
    document.querySelectorAll('.card-image').forEach(img => {
      img.style.viewTransitionName = 'none';
    });
    // Assigne le nom à la carte cliquée
    card.querySelector('.card-image').style.viewTransitionName = 'hero-image';
    card.querySelector('.card-title').style.viewTransitionName = 'hero-title';
  });
});

4. Le reveal circulaire

Le nouveau contenu se révèle dans un cercle qui s’agrandit depuis le point de clic. Effet spectaculaire pour les portfolios et sites créatifs.

/* CSS avec clip-path animé */
::view-transition-new(root) {
  animation: circle-reveal 0.6s ease-in-out;
}

@keyframes circle-reveal {
  from {
    clip-path: circle(0% at var(--click-x, 50%) var(--click-y, 50%));
  }
  to {
    clip-path: circle(150% at var(--click-x, 50%) var(--click-y, 50%));
  }
}

/* JavaScript pour capturer la position du clic */
document.addEventListener('click', (e) => {
  const x = (e.clientX / window.innerWidth) * 100;
  const y = (e.clientY / window.innerHeight) * 100;
  document.documentElement.style.setProperty('--click-x', x + '%');
  document.documentElement.style.setProperty('--click-y', y + '%');
});

5. Le stagger (éléments décalés)

Les éléments de la nouvelle page apparaissent un par un avec un léger décalage. Effet professionnel pour les pages avec des grilles ou listes.

/* Assignez des noms de transition numérotés */
.grid-item:nth-child(1) { view-transition-name: item-1; }
.grid-item:nth-child(2) { view-transition-name: item-2; }
.grid-item:nth-child(3) { view-transition-name: item-3; }
/* ... */

/* Animez avec des délais croissants */
::view-transition-new(item-1) {
  animation: stagger-in 0.4s ease-out 0.05s both;
}
::view-transition-new(item-2) {
  animation: stagger-in 0.4s ease-out 0.1s both;
}
::view-transition-new(item-3) {
  animation: stagger-in 0.4s ease-out 0.15s both;
}

@keyframes stagger-in {
  from { opacity: 0; transform: translateY(20px) scale(0.95); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

Intégration avec les frameworks modernes

Next.js (App Router)

// app/template.tsx — Wrapper de transition
'use client';
import { usePathname } from 'next/navigation';
import { useEffect, useRef } from 'react';

export default function Template({ children }) {
  const pathname = usePathname();
  const prevPathname = useRef(pathname);
  
  useEffect(() => {
    if (prevPathname.current !== pathname) {
      // La View Transitions API gère l'animation
      if (document.startViewTransition) {
        document.startViewTransition();
      }
      prevPathname.current = pathname;
    }
  }, [pathname]);
  
  return children;
}

Astro (support natif)

Astro offre le meilleur support natif des View Transitions parmi les frameworks :

---
// layout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html>
  <head>
    <ViewTransitions />
  </head>
  <body>
    <!-- Transition automatique sur l'image -->
    <img transition:name="hero" src="..." />
    
    <!-- Garde le header persistant (pas de transition) -->
    <header transition:persist>...</header>
    
    <!-- Animation personnalisée -->
    <main transition:animate="slide">
      <slot />
    </main>
  </body>
</html>

Barba.js — Pour les sites classiques (WordPress, HTML statique)

Si la View Transitions API n’est pas supportée par vos navigateurs cibles, Barba.js est l’alternative JavaScript la plus fiable :

// Installation : npm install @barba/core gsap
import barba from '@barba/core';
import gsap from 'gsap';

barba.init({
  transitions: [{
    name: 'default',
    leave(data) {
      return gsap.to(data.current.container, {
        opacity: 0,
        y: -20,
        duration: 0.3,
        ease: 'power2.in'
      });
    },
    enter(data) {
      return gsap.from(data.next.container, {
        opacity: 0,
        y: 20,
        duration: 0.3,
        ease: 'power2.out'
      });
    }
  }]
});

Performance et accessibilité

Respecter les préférences utilisateur

/* Désactiver les animations pour les utilisateurs sensibles */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
  
  /* Alternative : transition instantanée sans mouvement */
  ::view-transition-old(root) {
    animation: fade-out 0.01s;
  }
  ::view-transition-new(root) {
    animation: fade-in 0.01s;
  }
}

Optimisation des performances

  • Durée optimale : 200-500ms. En dessous de 200ms, la transition est à peine perceptible. Au-dessus de 500ms, elle ralentit l’expérience
  • Propriétés performantes uniquement : Animez transform et opacity. Évitez width, height, top, left qui déclenchent des recalculs de layout coûteux
  • will-change avec parcimonie : Ajoutez will-change: transform uniquement aux éléments qui vont être animés, et retirez-le après l’animation
  • Préchargement : Pour les transitions de page, préchargez la page suivante au survol du lien avec <link rel="prefetch"> — la transition sera instantanée

Courbes d’easing recommandées

  • ease-out (par défaut) — Rapide au début, ralentit à la fin. Idéal pour les éléments qui entrent dans l’écran
  • ease-in — Lent au début, accélère à la fin. Pour les éléments qui quittent l’écran
  • cubic-bezier(0.4, 0, 0.2, 1) — L’easing Material Design. Naturel et fluide, adapté à la plupart des cas
  • cubic-bezier(0.22, 1, 0.36, 1) — Easing « snappy ». Début rapide, fin douce. Donne une sensation de réactivité

Les transitions de page fluides ne sont plus un luxe réservé aux sites d’agences créatives. Avec la View Transitions API native, quelques lignes de CSS suffisent pour transformer l’expérience de navigation de n’importe quel site. Commencez par un simple crossfade, puis expérimentez avec les transitions d’éléments partagés pour créer des expériences vraiment mémorables.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité