Créer un hero de blog avec article vedette en React
Un hero de blog avec article vedette en React affiche une grande carte avec image plein-cadre, un overlay dégradé ancré en bas et des chips de métadonnées, puis liste les articles secondaires dans une grille responsive en dessous. Les animations d'entrée se jouent une fois au scroll via Framer Motion whileInView.
- Stack : React + Framer Motion 11 + Lucide React, ~135 lignes, zéro dépendance supplémentaire.
- L'overlay dégradé utilise un linear-gradient CSS de var(--color-background) vers transparent, il s'adapte à tous les thèmes.
- Les articles secondaires utilisent une grille CSS auto-fill (minmax 320px) pour un comportement responsive entièrement fluide.
- Accessible : les images ont un alt vide (décoratives) ; le contenu texte n'est jamais masqué par l'overlay.
- Supporte les thèmes clair et sombre via les CSS custom properties (themeMode: both).
Blog Hero Featured ouvre une page de blog ou de magazine avec une grande carte d'article qui s'impose dans la vue, puis passe le relais à une rangée d'articles secondaires en dessous. La carte vedette superpose une image plein-cadre, un dégradé bas qui garde le texte lisible sur n'importe quelle photo, et une bande de métadonnées avec auteur, date, temps de lecture et chips de catégorie, le tout entrant une seule fois au défilement.
Anatomie
Le composant se structure en deux blocs : une grande carte vedette pleine largeur et une grille optionnelle d'articles secondaires. La carte contient un conteneur d'image en ratio 2:1, un scrim dégradé positionné en absolu qui monte depuis la couleur de fond, et une couche de contenu épinglée en bas avec des chips en flex-wrap, un titre mis à l'échelle par clamp, un paragraphe d'extrait et une ligne auteur. Les articles secondaires sont des cartes flex horizontales avec une miniature 120x80px, un libellé de catégorie, un titre et une icône ArrowRight poussée au bout.
Comment ça marche
Le whileInView + viewport once:true de Framer Motion gère toutes les animations d'entrée sans aucun écouteur de défilement manuel. La carte vedette monte de 24px en fondu (opacité 0 à 1) avec une courbe personnalisée de 0,7s [0.16, 1, 0.3, 1]. Chaque article secondaire se décale avec un délai de 0,08s par index en plus d'un offset de base de 0,1s, créant une cascade. L'overlay dégradé est un simple gradient CSS de var(--color-background) à 0% vers transparent à 60%, il se lit correctement dans n'importe quel thème sans une seule ligne de JS.
Comment le coder en React
Créer la coque de la carte vedette
Enveloppe la carte dans un motion.a avec opacity:0 y:24 en initial et une animation vers opacity:1 y:0 via whileInView. Donne-lui position:relative, borderRadius depuis ton token de design, overflow:hidden et un conteneur d'image en ratio 2:1.
<motion.a initial={{ opacity: 0, y: 24 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.7, ease: [0.16, 1, 0.3, 1] }} style={{ position: "relative", borderRadius: "var(--radius-xl)", overflow: "hidden" }} >Ajouter l'overlay dégradé
Place une div absolue couvrant toute la carte avec un linear-gradient de var(--color-background) à 0% vers transparent à 60%. Comme tu utilises le token de fond du thème, l'overlay fonctionne en mode clair et sombre automatiquement.
<div style={{ position: "absolute", inset: 0, background: "linear-gradient(to top, var(--color-background) 0%, transparent 60%)" }} />Épingler les métadonnées en bas
Ajoute une div de contenu avec position:absolute, bottom/left/right 0 et du padding. À l'intérieur, rends le chip de catégorie avec un fond accent, les chips de tags optionnels, le titre avec clamp(1.5rem, 3.5vw, 2.5rem) pour un redimensionnement fluide, l'extrait et la ligne auteur avec les icônes Clock et User de Lucide React.
Construire la grille secondaire décalée
Rends les articles secondaires dans une grille CSS avec gridTemplateColumns: repeat(auto-fill, minmax(320px, 1fr)). Chaque article est un motion.a avec un délai de décalage : 0,1 + index * 0,08. Le layout flex à l'intérieur place une miniature de taille fixe à gauche et le contenu texte dans l'espace restant.
transition={{ duration: 0.5, delay: 0.1 + i * 0.08, ease: [0.16, 1, 0.3, 1] }}
Quand l'utiliser
Utilise cette section comme bloc d'ouverture de tout blog, site d'actualités ou plateforme de contenu où la hiérarchie éditoriale compte. Elle fonctionne bien sur les blogs produit SaaS, les portfolios d'agences avec études de cas et les publications médias. À éviter sur les homepages dont l'objectif principal est la conversion produit plutôt que la découverte de contenu, et passe-toi de la grille secondaire si tu as moins de deux articles d'appoint à afficher.
Utilisé par
- Vercel, Carte d'article vedette plein-cadre avec overlay dégradé et métadonnées auteur en haut de l'index du blog.
- Stripe, Grand post hero avec image, chip de catégorie et temps de lecture au-dessus d'une grille d'articles secondaires.
- Linear, Carte d'article vedette avec une typographie marquée superposée à une image de couverture, cohérente avec l'esthétique produit.
- Loom, Post de blog hero avec image pleine largeur et cartes d'articles secondaires décalées sous la ligne de flottaison.
FAQ
Comment l'overlay dégradé reste-t-il lisible en mode sombre ?
Le dégradé part de var(--color-background), pas d'une couleur en dur. Quand le thème change, ce token se met à jour automatiquement, donc le scrim se fond toujours dans le fond réel de la page sans JavaScript supplémentaire.
Peut-on supprimer la grille d'articles secondaires ?
La prop secondaryArticles vaut un tableau vide par défaut et la grille ne s'affiche que si ce tableau contient au moins un élément, donc tu peux omettre la prop sans risque et la carte vedette se suffit à elle-même.
Comment éviter que l'animation se rejoue à chaque défilement ?
Le flag viewport: { once: true } sur chaque élément motion whileInView garantit que l'animation d'entrée se joue exactement une fois quand l'élément entre dans la vue pour la première fois, puis reste dans son état final.
Le titre de la carte vedette se redimensionne-t-il sur mobile ?
Le titre utilise clamp(1.5rem, 3.5vw, 2.5rem), donc il rétrécit de façon fluide jusqu'à 24px sur les petits écrans sans media query. L'extrait est limité à 640px de largeur max pour ne jamais s'étirer inconfortablement sur les grandes vues.