Skip to content

Module 15 : Librairies JavaScript externes et Anime.js

Introduction

Ce module présente le concept des librairies JavaScript externes et la façon de les intégrer dans un projet via un CDN (Content Delivery Network). À travers la librairie Anime.js, vous apprendrez à créer des animations fluides et professionnelles sans avoir à tout coder manuellement, tout en conservant la structure de projet habituelle du cours.

Objectifs du cours

  • Comprendre ce qu'est une librairie JavaScript externe et pourquoi en utiliser une
  • Savoir intégrer une librairie via un CDN dans un projet HTML/CSS/JS
  • Intégrer Anime.js dans un projet simple
  • Produire différents types d'animations : déplacement, rebond, fondu, délai, combinaison de propriétés

Théorie

1 : Les librairies JavaScript externes

Définition

Une librairie JavaScript externe est un ensemble de fonctions et d'outils préconçus, créés par d'autres développeurs, que l'on peut inclure dans son propre projet pour accomplir certaines tâches plus facilement et rapidement.

Contexte d'utilisation

Certaines opérations courantes en développement web sont complexes à implémenter soi-même : tableaux de données interactifs, animations avancées, glisser-déposer (drag and drop), graphiques, etc. Plutôt que de repartir de zéro, on peut intégrer une librairie qui résout déjà ce problème.

Exemples de librairies populaires et leurs usages :

LibrairieUsage principal
Anime.jsAnimations JavaScript avancées
Chart.jsGraphiques et visualisations de données
SortableJSGlisser-déposer (drag and drop)
DataTablesTableaux interactifs (tri, recherche, pagination)
SwiperCarrousels et sliders tactiles

Points importants

  • Chaque librairie possède sa propre documentation officielle à consulter

2 : Le CDN (Content Delivery Network)

Définition

Un CDN est un réseau de serveurs distribués géographiquement qui héberge des fichiers (JavaScript, CSS, images, etc.) et les livrent rapidement à l'utilisateur depuis le serveur le plus proche. Inclure une librairie via un CDN signifie qu'on ne télécharge pas la librairie localement : on pointe directement vers son URL publique.

Le principal avantage d'utiliser un CDN est la simplicité : il suffit d'ajouter une balise <script> dans le HTML pour inclure la librairie, sans avoir à gérer les fichiers localement.

Comment inclure une librairie via CDN

On ajoute simplement une balise <script> dans le fichier HTML, avant les scripts qui utiliseront cette librairie.

html
<!-- Librairie externe chargée en premier -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>

<!-- Nos propres fichiers JS chargés ensuite -->
<script src="js/scripts.js"></script>

Important : L'ordre des balises <script> dans le HTML est crucial. La librairie externe doit toujours être déclarée avant les scripts qui l'utilisent, sans quoi le navigateur ne reconnaîtra pas les fonctions de la librairie.


3 : Exemple d'une librairie externe : Anime.js

Définition

Anime.js est une librairie JavaScript légère qui permet de créer des animations fluides sur des éléments HTML en modifiant leurs propriétés CSS (position, opacité, couleur, rotation, etc.) selon une ligne du temps configurable.

Contexte d'utilisation

Anime.js est utile lorsque les animations CSS simples (transition ou @keyframes) ne suffisent plus : enchaînement d'animations, délais échelonnés sur plusieurs éléments, contrôle programmatique (démarrer, mettre en pause, rejouer).

Syntaxe de base

La fonction principale est anime({...}). On lui passe un objet de configuration :

javascript
anime({
    targets: '#mon-element',   // L'élément à animer (sélecteur CSS ou objet DOM)
    translateX: 250,            // Propriété à animer et valeur cible
    duration: 1000,             // Durée en millisecondes
    easing: 'easeInOutQuad'    // Courbe d'accélération
});

Propriétés les plus utilisées

PropriétéDescriptionExemple
targetsÉlément(s) à animer'#boite', '.carte'
translateXDéplacement horizontal (px)250
translateYDéplacement vertical (px)-100
rotateRotation'1turn', '45deg'
scaleMise à l'échelle1.5
opacityOpacité (0 à 1)[0, 1]
backgroundColorCouleur de fond'#e74c3c'
durationDurée en millisecondes1000
delayDélai avant le départ (ms)500
easingCourbe d'accélération'easeOutBounce'
loopRépétitiontrue, 3
directionSens de l'animation'alternate'

Pour toute la documentation sur Anime.js (v3), consultez : https://animejs.com/v3/documentation/

Valeurs d'easing fréquentes

ValeurEffet
'linear'Vitesse constante
'easeInOutQuad'Accélération douce au départ et à l'arrivée
'easeOutBounce'Rebond à l'arrivée
'easeOutElastic'Effet élastique à l'arrivée
'easeInOutSine'Courbe sinusoïdale douce
'spring(1, 80, 10, 0)'Physique de ressort personnalisable

4 : Intégrer Anime.js dans un projet simple

Structure du projet

mon-projet/
├── index.html
├── css/
│   └── styles.css
└── js/
    └── scripts.js

Dans index.html — inclusion du CDN

Le CDN d'Anime.js doit être placé avant votre propre fichier JS, idéalement juste avant la fermeture de </body> :

html
<!-- Anime.js via CDN (doit être chargé avant scripts.js) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>

<!-- Votre propre fichier JS -->
<script src="js/scripts.js"></script>

Exemole code HTML

html
<button id="btn-animer">Animer</button>

<div id="div1">
    <h2>Div 1</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur, quia!</p>
    <img src="https://placehold.co/200x200" alt="Placeholder Image">
</div>

Dans scripts.js — utilisation avec init()

javascript
function animer() {
    anime({
        targets: '#ma-boite',
        translateX: 200,
        duration: 1000,
        easing: 'easeInOutQuad'
    });
}

function init() {
    document.getElementById('btn-animer').addEventListener('click', animer);
}

addEventListener('load', init);

5 : Anime.js avec plusieurs fichiers JavaScript

Contexte d'utilisation

Dans un projet réel, vous aurez souvent plusieurs fichiers JavaScript : l'un pour la logique du site, un autre pour les animations, etc. Il faut s'assurer que le CDN est chargé avant tous ces fichiers.

Structure du projet avec plusieurs fichiers JS

mon-projet/
├── index.html
├── css/
│   └── styles.css
└── js/
    ├── app.js          ← Logique principale du site
    └── animations.js   ← Animations avec Anime.js

Dans index.html — ordre d'inclusion

html
<!-- 1. Anime.js CDN en premier -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>

<!-- 2. Vos fichiers JS dans l'ordre souhaité -->
<script src="js/app.js"></script>
<script src="js/animations.js"></script>

Dans app.js — code existant du site

javascript
function afficherMessage() {
    document.getElementById('message').textContent = 'Bienvenue sur le site !';
}

function init() {
    document.getElementById('btn-message').addEventListener('click', afficherMessage);
}

addEventListener('load', init);

Dans animations.js — animations Anime.js

javascript
function animerTitre() {
    anime({
        targets: '#titre-principal',
        translateY: [-30, 0],
        opacity: [0, 1],
        duration: 800,
        easing: 'easeOutQuad'
    });
}

function init() {
    animerTitre();
}

addEventListener('load', init);

Note : Chaque fichier peut avoir sa propre fonction init() et son propre addEventListener('load', init). Le navigateur appellera les deux au chargement de la page, sans conflit. Chaque init est locale à son fichier et s'exécutera indépendamment.


Exemples d'animations avec Anime.js

Attention : les exemples suivants utilisent la syntaxe d'Anime.js 3.x et peuvent ne pas fonctionner avec les versions plus récentes. Assurez-vous d'utiliser la version 3.x du CDN pour tester ces exemples :
https://animejs.com/v3/documentation/

Déplacement horizontal simple

Anime un élément qui se déplace de 250px vers la droite au clic.

HTML

html
<div class="boite" id="boite-deplacement"></div>
<button id="btn-deplacement">Déplacer</button>

CSS

css
.boite {
    width: 80px;
    height: 80px;
    background-color: #3498db;
    border-radius: 8px;
    margin-bottom: 10px;
}

JavaScript

javascript
function deplacerHorizontal() {
    anime({
        targets: '#boite-deplacement',
        translateX: 250
    });
}

function init() {
    document.getElementById('btn-deplacement').addEventListener('click', deplacerHorizontal);
}

addEventListener('load', init);

Animation avec durée personnalisée

Même déplacement, mais ralenti à 2 secondes avec une vitesse linéaire.

JavaScript

javascript
function deplacerLentement() {
    anime({
        targets: '#boite-duree',
        translateX: 300,
        duration: 2000,
        easing: 'linear'
    });
}

function init() {
    document.getElementById('btn-duree').addEventListener('click', deplacerLentement);
}

addEventListener('load', init);

Effet "bounce" (rebond à l'arrivée)

L'élément monte puis rebondit à la fin de l'animation.

JavaScript

javascript
function animerBounce() {
    anime({
        targets: '#boite-bounce',
        translateY: -150,
        duration: 900,
        easing: 'easeOutBounce'
    });
}

function init() {
    document.getElementById('btn-bounce').addEventListener('click', animerBounce);
}

addEventListener('load', init);

Animation combinée (plusieurs propriétés simultanées)

Déplacement, rotation et changement de couleur en même temps.

JavaScript

javascript
function animationCombinee() {
    anime({
        targets: '#boite-combinee',
        translateX: 220,
        rotate: '1turn',
        scale: 1.4,
        backgroundColor: '#e74c3c',
        duration: 1200,
        easing: 'easeInOutQuad'
    });
}

function init() {
    document.getElementById('btn-combinee').addEventListener('click', animationCombinee);
}

addEventListener('load', init);

Fade in (apparition progressive)

L'élément part d'une opacité de 0 (invisible) pour aller à 1 (visible).

HTML

html
<div class="panneau" id="panneau-fade">Contenu qui apparaît</div>
<button id="btn-fade">Faire apparaître</button>

CSS

css
.panneau {
    opacity: 0;
    padding: 20px;
    background-color: #2ecc71;
    color: white;
    border-radius: 8px;
    width: 250px;
    text-align: center;
    margin-bottom: 10px;
}

JavaScript

javascript
function fadein() {
    anime({
        targets: '#panneau-fade',
        opacity: [0, 1],
        duration: 1500,
        easing: 'easeInOutSine'
    });
}

function init() {
    document.getElementById('btn-fade').addEventListener('click', fadein);
}

addEventListener('load', init);

Animation de plusieurs éléments avec délai échelonné

Chaque élément démarre son animation avec un décalage de 150ms par rapport au précédent, grâce à anime.stagger().

HTML

html
<div class="boite-multi" id="boite-m1"></div>
<div class="boite-multi" id="boite-m2"></div>
<div class="boite-multi" id="boite-m3"></div>
<div class="boite-multi" id="boite-m4"></div>
<button id="btn-multi">Animer en cascade</button>

CSS

css
.boite-multi {
    width: 60px;
    height: 60px;
    background-color: #9b59b6;
    border-radius: 6px;
    margin-bottom: 8px;
}

JavaScript

javascript
function animerEnCascade() {
    anime({
        targets: '.boite-multi',
        translateX: 280,
        delay: anime.stagger(150),
        duration: 700,
        easing: 'easeOutQuad'
    });
}

function init() {
    document.getElementById('btn-multi').addEventListener('click', animerEnCascade);
}

addEventListener('load', init);

Note : anime.stagger(150) calcule automatiquement un délai croissant pour chaque élément ciblé : le 1er démarre à 0ms, le 2e à 150ms, le 3e à 300ms, etc.


Démonstration complète

Galerie animée avec Anime.js

Objectif

Créer une page avec une liste de cartes et un panneau de contrôle. Le fichier JS unique gère à la fois les interactions utilisateur (sélection/compteur) et les animations Anime.js.

Structure du projet VS Code :

mon-projet/
├── index.html
├── css/
│   └── styles.css
└── js/
    └── script.js          (logique + animations Anime.js)

index.html

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Galerie animée - Anime.js</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1 id="titre-principal">Galerie animée</h1>

    <div id="controles">
        <button id="btn-entree">Animer l'entrée</button>
        <button id="btn-reset">Réinitialiser</button>
        <p>Cartes sélectionnées : <span id="compteur">0</span></p>
    </div>

    <div id="galerie">
        <div class="carte" id="carte-1">
            <img src="https://placehold.co/200x140/3498db/ffffff?text=Carte+1" alt="Carte 1">
            <p>Carte 1</p>
        </div>
        <div class="carte" id="carte-2">
            <img src="https://placehold.co/200x140/e74c3c/ffffff?text=Carte+2" alt="Carte 2">
            <p>Carte 2</p>
        </div>
        <div class="carte" id="carte-3">
            <img src="https://placehold.co/200x140/2ecc71/ffffff?text=Carte+3" alt="Carte 3">
            <p>Carte 3</p>
        </div>
        <div class="carte" id="carte-4">
            <img src="https://placehold.co/200x140/9b59b6/ffffff?text=Carte+4" alt="Carte 4">
            <p>Carte 4</p>
        </div>
    </div>

    <!-- Anime.js CDN — doit être avant script.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
    <script src="js/script.js"></script>
</body>
</html>

css/styles.css

css
body {
    font-family: Arial, sans-serif;
    padding: 20px;
    background: #f0f0f0;
}

h1 {
    color: #333;
    opacity: 0;
}

#controles {
    display: flex;
    gap: 10px;
    margin: 20px 0;
    align-items: center;
}

button {
    padding: 8px 16px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background: #0056b3;
}

#galerie {
    display: flex;
    gap: 15px;
    flex-wrap: wrap;
}

.carte {
    background: white;
    border-radius: 8px;
    padding: 10px;
    text-align: center;
    cursor: pointer;
    opacity: 0;
    transform: translateY(20px);
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.carte:hover {
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.carte.selectionnee {
    border: 2px solid #e74c3c;
}

.carte img {
    border-radius: 4px;
    margin-bottom: 8px;
}

.carte p {
    margin: 0;
    font-weight: bold;
}

js/script.js

javascript
var compteurSelection = 0;

function toggleSelection(event) {
    var carte = event.currentTarget;
    carte.classList.toggle('selectionnee');

    if (carte.classList.contains('selectionnee')) {
        compteurSelection = compteurSelection + 1;
    } else {
        compteurSelection = compteurSelection - 1;
    }

    document.getElementById('compteur').textContent = compteurSelection;
}

function animerEntree() {
    anime({
        targets: '#titre-principal',
        opacity: [0, 1],
        translateY: [-20, 0],
        duration: 600,
        easing: 'easeOutQuad'
    });

    anime({
        targets: '.carte',
        opacity: [0, 1],
        translateY: [30, 0],
        delay: anime.stagger(120),
        duration: 700,
        easing: 'easeOutQuad'
    });
}

function reinitialiserAnimation() {
    var cartes = document.getElementsByClassName('carte');
    for (var i = 0; i < cartes.length; i++) {
        cartes[i].classList.remove('selectionnee');
    }
    compteurSelection = 0;
    document.getElementById('compteur').textContent = 0;

    anime({
        targets: '.carte',
        opacity: 0,
        translateY: 30,
        duration: 400,
        easing: 'easeInQuad'
    });
}

function init() {
    var cartes = document.getElementsByClassName('carte');
    for (var i = 0; i < cartes.length; i++) {
        cartes[i].addEventListener('click', toggleSelection);
    }

    document.getElementById('btn-entree').addEventListener('click', animerEntree);
    document.getElementById('btn-reset').addEventListener('click', reinitialiserAnimation);
}

addEventListener('load', init);

Résultat attendu

Au chargement, les cartes et le titre sont invisibles. Un clic sur « Animer l'entrée » fait apparaître le titre, puis les cartes en cascade du haut vers le bas. Les cartes sont cliquables pour les sélectionner (bordure rouge) et le compteur se met à jour. Le bouton « Réinitialiser » efface les sélections et les cartes disparaissent en fondu.

  • Le titre apparaît avec un glissement depuis le haut
  • Les 4 cartes apparaissent en cascade avec un délai de 120ms entre chacune
  • Le clic sur une carte la sélectionne (bordure rouge) et incrémente le compteur
  • Un seul fichier script.js gère toute la logique et les animations

Exercices pratiques

Exercice 1 : Balle rebondissante

Avant de commencer

Cet exercice nécessite d'inclure le CDN d'Anime.js dans votre fichier HTML avant votre propre script JS.

Énoncé

Créer une page avec un cercle coloré et trois boutons : « Rebondir », « Tourner » et « Réinitialiser ». Chaque bouton déclenche une animation différente sur le cercle.

Fichiers à créer

  • index.html
  • css/styles.css
  • js/scripts.js

Consignes

  1. Créer un élément div avec la classe balle qui représente un cercle (utiliser border-radius: 50%)
  2. Inclure le CDN d'Anime.js avant votre fichier scripts.js
  3. Le bouton « Rebondir » anime la balle vers le haut (translateY) avec un easing easeOutBounce
  4. Le bouton « Tourner » anime la balle avec une rotation de 1turn en 800ms
  5. Le bouton « Réinitialiser » remet la balle à sa position et rotation initiales (translateY: 0, rotate: 0) en 400ms

Exercice 2 : Menu animé à l'entrée

Énoncé

Créer une page de présentation dont les éléments du menu de navigation apparaissent en cascade au chargement de la page, avec un effet de glissement depuis la gauche.

Fichiers à créer

  • index.html
  • css/styles.css
  • js/scripts.js

Consignes

  1. Créer une barre de navigation avec au moins 4 liens (<a>) ayant tous la même classe (ex : .nav-lien)
  2. Au chargement de la page (dans init()), déclencher automatiquement une animation sur tous les liens
  3. Chaque lien doit partir de translateX: -80 et opacity: 0 pour aller à leur position et opacité naturelles
  4. Utiliser anime.stagger(100) pour échelonner les délais
  5. Utiliser l'easing easeOutQuad avec une durée de 600ms

Exercice 3 : Tableau de bord animé

Énoncé

Créer une page « tableau de bord » avec des cartes de statistiques (ex. : ventes, visites, abonnés, revenus). Un seul fichier JS gère la mise à jour des valeurs et les animations Anime.js.

Fichiers à créer

  • index.html
  • css/styles.css
  • js/script.js (mise à jour des valeurs + animations Anime.js)

Consignes

  1. Créer 4 cartes avec un titre, une valeur numérique et une couleur distinctive (utiliser placehold.co si des images sont nécessaires)
  2. Au clic sur un bouton « Actualiser », mettre à jour les valeurs numériques des cartes avec de nouvelles valeurs fixes
  3. Au chargement, animer l'apparition des cartes en cascade (fade in + translateY)
  4. Au survol d'une carte (mouseover), lui appliquer une animation de mise à l'échelle (scale: 1.05) en 200ms
  5. Au retrait du survol (mouseout), remettre l'échelle à 1 en 200ms
  6. S'assurer que le CDN d'Anime.js est chargé avant script.js dans le HTML

Correction

Correction Exercice 1

Voir le code complet

index.html

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Balle rebondissante - Anime.js</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1>Balle rebondissante</h1>
    <div class="balle" id="balle"></div>
    <div class="controles">
        <button id="btn-rebondir">Rebondir</button>
        <button id="btn-tourner">Tourner</button>
        <button id="btn-reset">Réinitialiser</button>
    </div>

    <!-- Anime.js CDN — doit être avant script.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
    <script src="js/scripts.js"></script>
</body>
</html>

css/styles.css

css
body {
    font-family: Arial, sans-serif;
    text-align: center;
    padding: 20px;
    background: #f0f0f0;
}

h1 {
    color: #333;
    margin-bottom: 30px;
}

.balle {
    width: 80px;
    height: 80px;
    background: #3498db;
    border-radius: 50%;
    margin: 30px auto;
}

.controles {
    display: flex;
    gap: 10px;
    justify-content: center;
    margin-top: 20px;
}

button {
    padding: 10px 20px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
}

button:hover {
    background: #2980b9;
}

js/scripts.js

javascript
function rebondir() {
    anime({
        targets: '#balle',
        translateY: -150,
        duration: 800,
        easing: 'easeOutBounce'
    });
}

function tourner() {
    anime({
        targets: '#balle',
        rotate: '1turn',
        duration: 800,
        easing: 'easeInOutQuad'
    });
}

function reinitialiser() {
    anime({
        targets: '#balle',
        translateY: 0,
        rotate: 0,
        duration: 400,
        easing: 'easeInOutQuad'
    });
}

function init() {
    document.getElementById('btn-rebondir').addEventListener('click', rebondir);
    document.getElementById('btn-tourner').addEventListener('click', tourner);
    document.getElementById('btn-reset').addEventListener('click', reinitialiser);
}

addEventListener('load', init);

Explications

Cet exercice démontre l'utilisation basique d'Anime.js avec trois animations différentes : un rebond vertical avec easeOutBounce, une rotation complète, et une remise à zéro. Chaque fonction anime une propriété différente de la balle (position verticale, rotation, ou les deux). L'ordre des scripts dans le HTML est crucial pour que Anime.js soit disponible.


Correction Exercice 2

Voir le code complet

index.html

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Menu animé - Anime.js</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <nav>
        <ul>
            <li><a href="#" class="nav-lien">Accueil</a></li>
            <li><a href="#" class="nav-lien">À propos</a></li>
            <li><a href="#" class="nav-lien">Services</a></li>
            <li><a href="#" class="nav-lien">Contact</a></li>
        </ul>
    </nav>

    <!-- Anime.js CDN — doit être avant script.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
    <script src="js/script.js"></script>
</body>
</html>

css/styles.css

css
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    background: #f8f9fa;
}

nav {
    background: #343a40;
    padding: 1rem;
    border-radius: 8px;
}

nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: 2rem;
    justify-content: center;
}

nav a {
    color: white;
    text-decoration: none;
    padding: 0.5rem 1rem;
    border-radius: 4px;
    transition: background-color 0.3s;
    opacity: 0;
    transform: translateX(-80px);
}

nav a:hover {
    background: #495057;
}

js/script.js

javascript
function animerMenu() {
    anime({
        targets: '.nav-lien',
        translateX: [0, 0],
        opacity: [0, 1],
        delay: anime.stagger(100),
        duration: 600,
        easing: 'easeOutQuad'
    });
}

function init() {
    animerMenu();
}

addEventListener('load', init);

Explications

L'animation du menu utilise anime.stagger(100) pour créer un effet d'entrée en cascade où chaque lien apparaît avec un décalage de 100ms. Les liens partent d'une position décalée vers la gauche (translateX: -80px dans le CSS) et d'une opacité de 0, pour arriver à leur position finale. L'animation se déclenche automatiquement au chargement de la page dans la fonction init().


Correction Exercice 3

Voir le code complet

index.html

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tableau de bord animé - Anime.js</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1>Tableau de bord</h1>
    <button id="btn-actualiser">Actualiser</button>

    <div class="tableau-bord">
        <div class="carte" id="carte-ventes">
            <h3>Ventes</h3>
            <div class="valeur" id="valeur-ventes">1250</div>
        </div>
        <div class="carte" id="carte-visites">
            <h3>Visites</h3>
            <div class="valeur" id="valeur-visites">8750</div>
        </div>
        <div class="carte" id="carte-abonnes">
            <h3>Abonnés</h3>
            <div class="valeur" id="valeur-abonnes">320</div>
        </div>
        <div class="carte" id="carte-revenus">
            <h3>Revenus</h3>
            <div class="valeur" id="valeur-revenus">15420</div>
        </div>
    </div>

    <!-- Anime.js CDN — doit être avant script.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
    <script src="js/script.js"></script>
</body>
</html>

css/styles.css

css
body {
    font-family: Arial, sans-serif;
    padding: 20px;
    background: #f8f9fa;
    text-align: center;
}

h1 {
    color: #333;
    margin-bottom: 20px;
}

#btn-actualiser {
    padding: 10px 20px;
    background: #28a745;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    margin-bottom: 30px;
}

#btn-actualiser:hover {
    background: #218838;
}

.tableau-bord {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 20px;
    max-width: 800px;
    margin: 0 auto;
}

.carte {
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    opacity: 0;
    transform: translateY(30px);
    cursor: pointer;
    transition: box-shadow 0.3s;
}

.carte:hover {
    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
}

.carte:nth-child(1) { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.carte:nth-child(2) { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
.carte:nth-child(3) { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
.carte:nth-child(4) { background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); }

.carte h3 {
    color: white;
    margin: 0 0 10px 0;
    font-size: 18px;
}

.valeur {
    font-size: 32px;
    font-weight: bold;
    color: white;
}

js/script.js

javascript
function animerEntreeCartes() {
    anime({
        targets: '.carte',
        opacity: [0, 1],
        translateY: [30, 0],
        delay: anime.stagger(150),
        duration: 800,
        easing: 'easeOutQuad'
    });
}

function animerSurvolCarte(event) {
    anime({
        targets: event.currentTarget,
        scale: 1.05,
        duration: 200,
        easing: 'easeOutQuad'
    });
}

function animerSortieCarte(event) {
    anime({
        targets: event.currentTarget,
        scale: 1,
        duration: 200,
        easing: 'easeOutQuad'
    });
}

function actualiserValeurs() {
    // Valeurs fixes pour la démonstration
    const nouvellesValeurs = {
        ventes: 1420,
        visites: 9200,
        abonnes: 385,
        revenus: 17850
    };

    anime({
        targets: '#valeur-ventes',
        innerHTML: nouvellesValeurs.ventes,
        duration: 500,
        easing: 'easeOutQuad'
    });

    anime({
        targets: '#valeur-visites',
        innerHTML: nouvellesValeurs.visites,
        duration: 500,
        easing: 'easeOutQuad'
    });

    anime({
        targets: '#valeur-abonnes',
        innerHTML: nouvellesValeurs.abonnes,
        duration: 500,
        easing: 'easeOutQuad'
    });

    anime({
        targets: '#valeur-revenus',
        innerHTML: nouvellesValeurs.revenus,
        duration: 500,
        easing: 'easeOutQuad'
    });
}

function init() {
    animerEntreeCartes();

    const cartes = document.getElementsByClassName('carte');
    for (let i = 0; i < cartes.length; i++) {
        cartes[i].addEventListener('mouseover', animerSurvolCarte);
        cartes[i].addEventListener('mouseout', animerSortieCarte);
    }

    document.getElementById('btn-actualiser').addEventListener('click', actualiserValeurs);
}

addEventListener('load', init);

Explications

Ce tableau de bord combine plusieurs concepts : animation d'entrée en cascade pour les cartes, animations au survol, et mise à jour animée des valeurs. L'animation des valeurs utilise innerHTML comme propriété cible d'Anime.js pour créer un effet de compteur animé. Les cartes ont des couleurs de fond dégradées distinctives et réagissent au survol avec une mise à l'échelle.