Retour au catalogue

About Comparison

Avant/apres montrant la transformation de l'entreprise.

aboutmedium Both Responsive a11y
boldcorporatesaasagencyuniversalsplit
Theme

Créer une section comparaison avant/après en React

Une section comparaison avant/après en React affiche deux cartes dans une grille CSS (1fr auto 1fr) séparées par une flèche animée. Chaque carte apparaît en fade vers le haut au scroll via Framer Motion whileInView avec un délai décalé. La carte 'après' utilise une bordure accent pour mettre en valeur l'état amélioré.

  • Stack : React + Framer Motion + Tailwind v4 + lucide-react, ~75 lignes au total.
  • Animation : whileInView avec once:true, se déclenche une seule fois quand chaque carte entre dans le viewport.
  • L'icône flèche (lucide ArrowRight) passe de scale 0 à 1 avec 300ms de délai, créant un ordre de révélation naturel de gauche à droite.
  • Entièrement adaptatif au thème via les CSS custom properties ; aucune couleur codée en dur.
  • Sur mobile la grille passe en colonne unique ; la flèche reste visible entre les deux cartes.

About Comparison est une section React qui raconte l'histoire d'une transformation dans une mise en page côte à côte : une carte 'avant' à gauche, une flèche animée au centre, et une carte 'après' à droite. Chaque carte liste les métriques ou faits clés sous forme de lignes label/valeur, rendant l'écart entre deux états immédiatement lisible. Le fade-in déclenché au scroll maintient l'attention sans demander d'interaction autre que le défilement.

Anatomie

La section externe contient un bloc d'en-tête centré (badge, h2, sous-titre) suivi d'une grille à trois colonnes. La grille utilise le gabarit `1fr auto 1fr` pour que la colonne de la flèche ne prenne que l'espace strictement nécessaire. Chaque SideCard est une motion.div indépendante avec une bordure arrondie, une image optionnelle dans un conteneur en ratio 3:2 en haut, et une liste de paires label/valeur séparées par de fines règles horizontales. La carte 'après' reçoit une bordure accent colorée et un titre en couleur accent pour guider le regard.

Comment ça marche

Trois animations Framer Motion `whileInView` pilotent la révélation. L'en-tête monte en fade sans délai. La carte 'avant' suit 100ms plus tard. La carte 'après' apparaît à 200ms. La flèche entre elles utilise une animation scale distincte depuis 0, retardée à 300ms, pour qu'elle surgisse après que les deux cartes ont déjà commencé à entrer, renforçant la narration de gauche à droite. Toutes les animations utilisent `viewport={{ once: true }}` pour ne pas se rejouer au nouveau scroll.

Comment le coder en React

  1. Définir la forme des données

    Crée une interface `ComparisonSide` avec un label, une URL d'image optionnelle, et un tableau de `{ label, value }`. Passe `before` et `after` en props optionnelles pour que la section se dégrade proprement si un côté manque.

    interface ComparisonSide {
      label: string;
      image?: string;
      points: { label: string; value: string }[];
    }
  2. Construire le sous-composant SideCard

    Enveloppe la carte dans une `motion.div` avec `initial={{ opacity: 0, y: 30 }}` et `whileInView={{ opacity: 1, y: 0 }}`. Accepte un `delay` et un booléen `accent`. Quand `accent` est vrai, passe la bordure et le titre sur le token accent, cela distingue l'état 'après' sans classe supplémentaire.

    <motion.div
      initial={{ opacity: 0, y: 30 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true }}
      transition={{ delay, duration: 0.5 }}
      style={{
        borderColor: accent
          ? "var(--color-accent)"
          : "var(--color-border)",
      }}
    >
  3. Mettre en place la grille trois colonnes avec la flèche

    Utilise `grid-cols-[1fr_auto_1fr]` sur grand écran (colonne unique sur mobile). Entre les deux cartes, rends une `motion.div` qui passe de `scale: 0` à `scale: 1` avec 300ms de délai. Remplis un cercle de 48x48 avec l'arrière-plan accent et place l'icône ArrowRight à l'intérieur.

    <div className="grid grid-cols-1 lg:grid-cols-[1fr_auto_1fr] gap-6 items-center">
      <SideCard side={before} delay={0.1} accent={false} />
      <motion.div
        initial={{ opacity: 0, scale: 0 }}
        whileInView={{ opacity: 1, scale: 1 }}
        viewport={{ once: true }}
        transition={{ delay: 0.3, duration: 0.4 }}
      >
        <div className="flex h-12 w-12 items-center justify-center rounded-full"
          style={{ backgroundColor: "var(--color-accent)" }}>
          <ArrowRight style={{ color: "var(--color-background)" }} />
        </div>
      </motion.div>
      <SideCard side={after} delay={0.2} accent={true} />
    </div>
  4. Brancher l'en-tête et passer les vraies données

    Ajoute un en-tête centré au-dessus de la grille : un span badge, un h2, et un paragraphe sous-titre, chacun rendu conditionnellement. Anime le bloc entier comme une seule `motion.div` au délai 0. Passe ensuite tes vraies données avant/après, trois à cinq points par côté sont l'optimum de lisibilité.

Quand l'utiliser

Utilise cette section sur les landing pages SaaS, les pages portfolio d'agences, ou toute histoire produit où tu peux quantifier la transformation avec des métriques concrètes. Elle fonctionne mieux en milieu de page, après le hero, quand l'utilisateur a assez de contexte pour apprécier ce que les chiffres signifient. À éviter quand la différence avant/après ne peut pas s'exprimer en paires label/valeur courtes, une timeline ou une narration en prose convient mieux à ce cas. Ne pas placer deux de ces sections côte à côte sur la même page.

Utilisé par

  • Notion, Utilise des cartes de métriques côte à côte sur ses pages 'pour les équipes' pour montrer les gains de productivité avant et après adoption.
  • Linear, Emploie une mise en page avant/après structurée dans ses études de cas pour contraster les anciens workflows avec ceux propulsés par Linear.
  • Stripe, Utilise des mises en page comparatives sur ses pages produit Payments et Billing pour montrer la friction d'un ancien checkout face au flow Stripe.
  • Webflow, Présente des comparaisons avant/après de workflows développeur/designer pour positionner son builder no-code face aux sites codés à la main.

FAQ

Combien de points par côté inclure ?

Trois à cinq points représentent le bon équilibre. En dessous de trois, la carte paraît vide ; au-delà de cinq, les utilisateurs arrêtent de lire. Priorise les métriques qui comptent le plus pour ton lecteur cible.

Peut-on utiliser cette section sans l'image optionnelle ?

Oui. Le bloc image est protégé par `side.image &&` donc la carte s'affiche proprement sans lui. La liste de stats commence directement dans la zone de padding.

Comment changer la couleur accent de la carte 'après' ?

Le composant lit `var(--color-accent)` depuis le preset de thème actif. Change le thème au niveau de l'attribut `data-theme` et la bordure comme le titre se mettent à jour automatiquement.

L'animation se rejoue-t-elle quand l'utilisateur remonte la page ?

Non. Les trois motion.div utilisent `viewport={{ once: true }}`, donc chaque carte s'anime uniquement la première fois qu'elle entre dans le viewport.

"use client";

import React from "react";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";

interface ComparisonSide {
  label: string;
  image?: string;
  points: { label: string; value: string }[];
}

interface AboutComparisonProps {
  badge?: string;
  title?: string;
  subtitle?: string;
  before?: ComparisonSide;
  after?: ComparisonSide;
}

function SideCard({ side, delay, accent }: { side: ComparisonSide; delay: number; accent: boolean }) {
  return (

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Avis

Section avant/après React, Code + Tutoriel