Blog / CSS/JS

Carousel 3D en CSS et JavaScript

Apprenez a creer un carousel 3D rotatif avec les CSS transforms (perspective, preserve-3d, rotateY) et une navigation JavaScript fluide. Auto-rotation et support tactile inclus.

Introduction

Le carousel 3D est un composant visuel spectaculaire qui donne une veritable impression de profondeur a votre interface. Contrairement aux sliders classiques qui glissent de gauche a droite, un carousel 3D fait tourner les elements dans l'espace, creant une experience immersive.

Dans ce tutoriel, nous allons construire un carousel 3D complet, etape par etape. Nous couvrirons la structure HTML, les CSS 3D transforms, la navigation JavaScript, l'auto-rotation et le support tactile pour mobile.

💡
Bon a savoir

Les CSS 3D transforms sont supportees par tous les navigateurs modernes. Les proprietes cles sont perspective, transform-style: preserve-3d et les fonctions rotateY() / translateZ().

1. Structure HTML

La structure est simple : un conteneur scene qui definit la perspective, un conteneur carousel qui tourne, et des cellules positionnees dans l'espace 3D.

carousel.html
<!-- Conteneur scene : definit la perspective -->
<div class="carousel-scene">

  <!-- Conteneur carousel : tourne en 3D -->
  <div class="carousel-3d" id="carousel">
    <div class="carousel-cell">1</div>
    <div class="carousel-cell">2</div>
    <div class="carousel-cell">3</div>
    <div class="carousel-cell">4</div>
    <div class="carousel-cell">5</div>
    <div class="carousel-cell">6</div>
  </div>

</div>

<!-- Boutons de navigation -->
<div class="carousel-nav">
  <button onclick="rotateCarousel(-1)">Precedent</button>
  <button onclick="rotateCarousel(1)">Suivant</button>
</div>

Les trois niveaux de la structure

  • carousel-scene : le viewport 3D. C'est lui qui definit la propriete perspective pour creer la profondeur
  • carousel-3d : le conteneur rotatif. Il utilise transform-style: preserve-3d pour que ses enfants soient positionnes dans l'espace 3D
  • carousel-cell : chaque element du carousel, positionne avec rotateY() et translateZ()

2. CSS 3D Transforms

Le coeur du carousel repose sur les CSS 3D transforms. Chaque cellule est d'abord tournee autour de l'axe Y a un angle precis, puis poussee vers l'exterieur avec translateZ().

carousel-3d.css
/* Scene : definit la perspective 3D */
.carousel-scene {
  width: 320px;
  height: 220px;
  perspective: 1000px;
  position: relative;
}

/* Carousel : preserve-3d pour l'espace 3D */
.carousel-3d {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Cellule : positionnement absolu + centre */
.carousel-cell {
  position: absolute;
  width: 140px;
  height: 180px;
  left: 50%;
  top: 50%;
  margin-left: -70px;
  margin-top: -90px;
  border-radius: 16px;
  backface-visibility: hidden;
}

Comprendre perspective et preserve-3d

La propriete perspective controle l'intensite de l'effet 3D. Une valeur plus petite (ex: 500px) cree un effet de profondeur plus marque, tandis qu'une valeur plus grande (ex: 2000px) donne un rendu plus plat.

  • perspective: 1000px : valeur equilibree, bonne profondeur sans distorsion excessive
  • transform-style: preserve-3d : indispensable pour que les enfants soient dans l'espace 3D du parent
  • backface-visibility: hidden : masque les faces arrieres des cartes pour un rendu propre
🎨
Le calcul du rayon

Le rayon (translateZ) se calcule en fonction du nombre de cellules et de leur largeur. La formule est : rayon = (largeur / 2) / tan(PI / nbCellules). Pour 6 cellules de 140px, le rayon est d'environ 121px.

Positionnement des cellules

Chaque cellule est positionnee en combinant rotateY() et translateZ(). L'angle entre chaque cellule est de 360 / nombreDeCellules degres.

Le JavaScript se charge de deux choses : positionner les cellules a l'initialisation et gerer la rotation au clic sur les boutons de navigation.

carousel-3d.js
const carousel = document.getElementById('carousel');
const cells = carousel.querySelectorAll('.carousel-cell');
const cellCount = cells.length;
const theta = 360 / cellCount;
const cellWidth = 140;

// Calcul du rayon optimal
const radius = Math.round(
  (cellWidth / 2) /
  Math.tan(Math.PI / cellCount)
);

let currentIndex = 0;

// Positionner chaque cellule dans l'espace 3D
cells.forEach((cell, i) => {
  const angle = theta * i;
  cell.style.transform =
    `rotateY(${angle}deg) translateZ(${radius}px)`;
});

// Rotation du carousel
function rotateCarousel(direction) {
  currentIndex += direction;
  const angle = theta * currentIndex * -1;
  carousel.style.transform =
    `rotateY(${angle}deg)`;
}

Comment fonctionne la rotation

A chaque clic, on incremente ou decremente currentIndex. L'angle de rotation du conteneur est simplement theta * currentIndex * -1. Le signe negatif est important : pour montrer l'element suivant (a droite), le conteneur doit tourner dans le sens inverse.

La transition CSS transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1) assure une rotation fluide avec un easing naturel.

⚠️
Attention aux performances

Les CSS 3D transforms sont accelerees par le GPU, mais un trop grand nombre de cellules avec des ombres complexes peut impacter les performances. Limitez-vous a 6-8 cellules maximum pour un rendu fluide sur tous les appareils.

4. Auto-rotation

Pour rendre le carousel plus dynamique, ajoutons une rotation automatique qui se met en pause lorsque l'utilisateur interagit avec le composant.

auto-rotation.js
let autoRotateInterval = null;
const AUTO_ROTATE_DELAY = 3000; // 3 secondes

// Demarrer l'auto-rotation
function startAutoRotate() {
  stopAutoRotate();
  autoRotateInterval = setInterval(() => {
    rotateCarousel(1);
  }, AUTO_ROTATE_DELAY);
}

// Arreter l'auto-rotation
function stopAutoRotate() {
  if (autoRotateInterval) {
    clearInterval(autoRotateInterval);
    autoRotateInterval = null;
  }
}

// Pause au survol
const scene = document.querySelector('.carousel-scene');

scene.addEventListener('mouseenter', stopAutoRotate);
scene.addEventListener('mouseleave', startAutoRotate);

// Pause au clic sur les boutons
document.querySelectorAll('.carousel-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    stopAutoRotate();
    // Reprendre apres 5 secondes d'inactivite
    setTimeout(startAutoRotate, 5000);
  });
});

// Demarrer au chargement
startAutoRotate();

Le pattern est classique : un setInterval qui appelle rotateCarousel(1) toutes les 3 secondes. On le stoppe au survol de la souris ou au clic sur les boutons de navigation, et on le reprend automatiquement apres un delai d'inactivite.

💡
UX et auto-rotation

L'auto-rotation est utile pour capter l'attention, mais peut etre frustrante si l'utilisateur essaie de lire le contenu. Prevoyez toujours un mecanisme de pause explicite et reprenez la rotation uniquement apres un delai suffisant.

5. Touch/Swipe support

Pour une experience mobile optimale, ajoutons la detection des gestes swipe. L'utilisateur pourra faire tourner le carousel en balayant l'ecran avec son doigt.

touch-support.js
let touchStartX = 0;
let touchEndX = 0;
const SWIPE_THRESHOLD = 50; // pixels minimum

scene.addEventListener('touchstart', (e) => {
  touchStartX = e.changedTouches[0].screenX;
  stopAutoRotate();
}, { passive: true });

scene.addEventListener('touchend', (e) => {
  touchEndX = e.changedTouches[0].screenX;
  handleSwipe();
}, { passive: true });

function handleSwipe() {
  const diff = touchStartX - touchEndX;

  if (Math.abs(diff) > SWIPE_THRESHOLD) {
    if (diff > 0) {
      // Swipe gauche = element suivant
      rotateCarousel(1);
    } else {
      // Swipe droit = element precedent
      rotateCarousel(-1);
    }
  }

  // Reprendre l'auto-rotation apres 5s
  setTimeout(startAutoRotate, 5000);
}

Logique du swipe

Le fonctionnement est direct :

  1. On enregistre la position X du doigt au touchstart
  2. On la compare a la position au touchend
  3. Si la difference depasse le seuil (50px), on declenche une rotation
  4. Un swipe vers la gauche (diff positif) affiche l'element suivant

L'option { passive: true } sur les event listeners ameliore les performances en indiquant au navigateur qu'on n'appellera pas preventDefault().

⚠️
Gestion des conflits scroll/swipe

Si votre carousel est integre dans une page scrollable, le swipe horizontal peut interferer avec le scroll vertical. Ajoutez une detection de direction pour ne declencher la rotation que si le mouvement est majoritairement horizontal.

Bonnes pratiques

Avant de conclure, voici quelques recommandations pour creer un carousel 3D performant et accessible :

Performance

  • Limitez le nombre de cellules a 6-8 maximum pour eviter les ralentissements sur mobile
  • Utilisez will-change: transform sur le conteneur carousel pour optimiser le rendu GPU
  • Evitez les ombres complexes (box-shadow avec blur eleve) qui alourdissent le rendu 3D
  • Privilegiez transform et opacity pour les animations, car elles ne declenchent pas de reflow

Design

  • Fond sombre recommande : la perspective 3D ressort mieux sur des arriere-plans fonces
  • Taille adaptee : ajustez la perspective et le rayon pour que les cellules ne se chevauchent pas excessivement
  • Indicateur visuel : ajoutez des dots ou un compteur pour montrer la position actuelle
  • Transition fluide : utilisez un cubic-bezier personnalise plutot qu'un ease generique

Accessibilite

accessibility.css
/* Desactiver les animations pour les utilisateurs sensibles */
@media (prefers-reduced-motion: reduce) {
  .carousel-3d {
    transition: none;
  }
}

/* Focus visible pour navigation clavier */
.carousel-btn:focus-visible {
  outline: 2px solid #6366f1;
  outline-offset: 2px;
}

/* ARIA labels pour les lecteurs d'ecran */
/* <div role="region" aria-label="Carousel 3D"> */
/* <button aria-label="Element precedent"> */
/* <button aria-label="Element suivant"> */
  • Respectez prefers-reduced-motion en supprimant la transition et l'auto-rotation
  • Ajoutez des attributs ARIA : role="region", aria-label et aria-roledescription="carousel"
  • Navigation clavier : les fleches gauche/droite devraient permettre de naviguer dans le carousel

Conclusion

Le carousel 3D est un composant visuellement impressionnant qui combine les CSS 3D transforms et le JavaScript pour creer une experience interactive unique. En maitrisant perspective, preserve-3d, rotateY() et translateZ(), vous pouvez construire des interfaces qui se demarquent.

Les points cles a retenir :

  • La perspective definit l'intensite de l'effet 3D
  • Le rayon se calcule en fonction du nombre et de la taille des cellules
  • L'auto-rotation doit se mettre en pause lors des interactions utilisateur
  • Le support tactile est essentiel pour une experience mobile complete
  • L'accessibilite ne doit jamais etre negligee, meme sur des composants visuels
🎨
Allez plus loin

Decouvrez d'autres effets 3D interactifs dans notre bibliotheque d'effets, avec du code copiable en un clic et des demos en direct.