Skip to content

julienborgeon/fem-testimonials-grid-section

Repository files navigation

🇫🇷 Français · English

Frontend Mentor – Testimonials grid section (solution)

Vite Tailwind CSS v4 Netlify Live

Ce repo contient ma solution au défi Testimonials grid section de Frontend Mentor.

🎯 Objectif personnel : maîtriser CSS grid et les classes de pseudos-éléments de Tailwind V4.


🔎 Aperçu

Le challenge

Reproduire la section de témoignages en respectant le design et en garantissant :

  • un HTML sémantique et accessible ;
  • une grille responsive fidèle au layout desktop (choix de 4 colonnes) ;
  • un code clair et maintenable avec Tailwind v4.

Capture

Screenshot de la solution

Liens


🚀 Lancer le projet

npm install
npm run dev      # serveur local
npm run build    # build de production (dossier dist/)
npm run preview  # prévisualisation du build

🧱 Construit avec

  • HTML5 sémantique (main, ul/li, figure/figcaption/img pour les témoignages)
  • Tailwind CSS v4 (approche CSS-first avec @theme pour définir des tokens)
  • Mobile-first workflow
  • Polices locales WOFF2 (Barlow Semi Condensed 500/600) + font-display: swap
  • Vite (build performant, purge console/debugger, assets fingerprintés)
  • Netlify (headers de sécurité & cache via netlify.toml)

🧭 Démarche & choix d’implémentation

Structure HTML

1) Structure sémantique

Le composant entier est un groupe de citations attribuées. Le choix sémantique qui me paraît le plus pertinent est donc :

  • un landmark <section> avec un intitulé unique, référencé par aria-labelledby ;
  • une liste <ul> d’items <li> pour représenter l’ensemble des témoignages ;
  • chaque item est une figure autonome (<figure>) qui regroupe :
    • l’attribution dans <figcaption> (avatar, nom, statut) ;
    • la citation dans <blockquote> (titre/catchphrase + texte détaillé).

Ce schéma exprime explicitement « un ensemble de témoignages, chacun étant une citation avec son auteur », ce qui aide les lecteurs d’écran, la navigation par structure et reste portable (chaque figure peut vivre ailleurs dans le document si besoin).

Structure simplifiée

<section aria-labelledby="testimonials-heading">
  <h1 id="testimonials-heading" class="sr-only"></h1>
  <ul>
    <li>
      <figure>
        <figcaption>
          <img />
          <div>
            <h2></h2>
            <p></p>
          </div>
        </figcaption>
        <blockquote>
          <p></p>
          <p></p>
        </blockquote>
      </figure>
    </li>
    <!-- ... -->
  </ul>
</section>

Justification sémantique

  • <blockquote> porte la sémantique de citation ;
  • <figcaption> attribue la citation à son auteur et lie visuellement/structurellement l’avatar + le nom ;
  • <ul> annonce bien « plusieurs témoignages » (navigation par listes) ;
  • aria-labelledby relie le titre de section à son contenu.

ℹ️ figure n’est pas réservé aux images : il sert à regrouper un contenu autonome (photo, tableau, code, citation…). Ici, il renforce le lien sémantique citation + attribution sans surcharger la hiérarchie des titres.

2) Grille responsive (Tailwind v4)

Le layout desktop demande 4 colonnes avec des cartes qui s’étendent sur plusieurs colonnes/rangées. La grille repose sur le DOM mobile‑first (1 colonne) et des placements explicites au breakpoint xl.

<ul
  class="grid grid-cols-1 gap-8 md:grid-cols-2 md:grid-rows-[auto_auto] xl:auto-rows-fr xl:grid-cols-4"
>
  <!-- Daniel (large, 2 colonnes) -->
  <li class="xl:col-span-2">...</li>

  <!-- Jonathan (en haut, col 3) -->
  <li class="xl:col-start-3">...</li>

  <!-- Jeanette (bas, col 1) -->
  <li class="xl:col-start-1 xl:row-start-2">...</li>

  <!-- Patrick (large en bas, 2 colonnes, démarre col 2) -->
  <li class="xl:col-span-2 xl:col-start-2 xl:row-start-2">...</li>

  <!-- Kira (haute, à droite, 2 rangées) -->
  <li class="xl:col-start-4 xl:row-span-2">...</li>
</ul>

Points pratiques

  • xl:auto-rows-fr crée des rangées de hauteur uniforme ; couplé à h-full sur chaque figure, les cartes occupent toute la cellule.
  • On conserve l’ordre DOM logique (utile aux technologies d’assistance) et on n’utilise les col-start/row-span qu’au desktop.

♿ Accessibilité (A11y)

  • Groupe sémantique de témoignages : vraie <ul> de <li> (navigation par listes dans les lecteurs d’écran).
  • Citation attribuée : <blockquote> + <figcaption> dans une <figure> autonome.
  • Ordre DOM = ordre visuel (important pour une grille responsive).

⚡ Performance

  • Tailwind v4 JIT → CSS minimal.
  • Polices WOFF2 + preload ciblé + swap.
  • Vite : sourcemap: false, drop: ["console","debugger"], assetsInlineLimit: 0 pour éviter l’inlining d’assets.
  • Netlify : cache long sur assets fingerprintés/polices, en-têtes de sécurité pour la version en prod publiée pour la preview.

🧪 Ma démarche

Technologies utilisées

  • Semantic HTML5 markup
  • CSS custom properties (via tokens Tailwind v4 dans @theme)
  • Mobile-first workflow
  • Vite (bundler/build)
  • Tailwind CSS v4
  • Netlify (hébergement & headers)

Ce que j'ai appris

  • Qu’un <figure> ne sert pas uniquement aux images : c’est un conteneur sémantique pour un contenu autonome accompagné d’une légende/attribution via <figcaption>. Dans le cas d’un témoignage, regrouper <blockquote> + attribution dans figure renforce la relation logique et améliore l’accessibilité.
  • La modélisation d’un groupe de témoignages en liste réelle (<ul><li>) facilite la navigation et la compréhension du contenu par les technologies d’assistance.
  • La mise en page grid avec placements explicites (col-span, col-start, row-span) est parfaitement lisible avec Tailwind v4 et reste fidèle au mobile‑first.

Ressources utiles

👤 Auteur


🙌 Remerciements

Merci à Frontend Mentor pour le design du challenge et à la communauté pour les retours.
Un clin d’œil aux ressources MDN & Tailwind pour la clarté de leur doc.


📁 Structure du projet

└── 📁testimonials-grid-section
    └── 📁.vscode
        ├── settings.json
    └── 📁public
        └── 📁assets
            ├── bg-pattern-quotation.svg
            ├── favicon-32x32.png
            ├── image-daniel.jpg
            ├── image-jeanette.jpg
            ├── image-jonathan.jpg
            ├── image-kira.jpg
            ├── image-patrick.jpg
        └── 📁fonts
            ├── barlow-semi-condensed-v15-latin-500.woff2
            ├── barlow-semi-condensed-v15-latin-600.woff2
    └── 📁src
        ├── main.css
    ├── .gitattributes
    ├── .gitignore
    ├── .prettierrc
    ├── index.html
    ├── netlify.toml
    ├── package-lock.json
    ├── package.json
    ├── README.en.md
    ├── README.md
    └── vite.config.js

Releases

No releases published

Packages

 
 
 

Contributors