Aller au contenu

Premiers pas avec Tailwind

Objectif : mettre les mains dedans. Cinq exercices qui partent du code tout fait et te lâchent progressivement la main, jusqu'à ce que tu conçoives tes propres composants. Deux d'entre eux finiront dans ton portfolio.

Comment lire ce chapitre

Chaque exercice est découpé en paliers. Tu ne fais pas tous les paliers de tous les exercices au hasard : tu suis l'ordre.

Palier Ce que tu fais Ce que tu y gagnes
1 — Copie et observe Tu colles le code donné, puis tu modifies une ou deux classes imposées et tu regardes le résultat Tu vois ce que fait chaque classe, sans réfléchir à la mise en page
2 — Complète les trous Le code est là, avec des ??? à remplacer. Chaque trou est précédé d'un commentaire qui dit ce qu'on attend et propose trois candidates Tu choisis, donc tu décides. Plusieurs réponses sont justes
3 — À toi Une consigne, des critères, une banque de classes. Pas de code Tu conçois

Au palier 2, plusieurs réponses sont correctes. Les trois candidates proposées fonctionnent toutes techniquement : la question est de savoir laquelle sert ton intention. C'est exactement le travail du reste de l'année.

Astuce

Garde l'autocomplétion de Tailwind CSS IntelliSense ouverte pendant que tu remplis les trous : tape les premières lettres d'une candidate, VS Code te montre la couleur et la valeur CSS derrière. C'est plus rapide que la doc.

Setup

Ouvre src/App.vue et remplace tout son contenu par ceci. Toutes les sections des exercices viendront se poser à l'intérieur du <main>, les unes sous les autres.

<script setup>
  // Rien ici : on ne fait que du template et des classes.
</script>

<template>
  <main class="min-h-screen bg-stone-100 p-8">
    <h1 class="text-4xl font-bold tracking-tight text-zinc-900 mb-10">
      Mes exercices Tailwind
    </h1>

    <!-- Tes sections d'exercices viennent ici -->

  </main>
</template>

Lance le serveur si ce n'est pas déjà fait :

npm run dev

Et ouvre http://localhost:5173.

Exercice 1 — Boutons

Durée indicative : 45 minutes.

Palier 1 — Copie et observe

Colle cette section dans ton <main> :

<section class="mb-12">
  <h2 class="text-2xl font-bold text-zinc-900 mb-4">Boutons</h2>
  <div class="flex flex-wrap gap-4">
    <button class="bg-zinc-900 text-stone-50 px-5 py-2.5 rounded-full font-medium hover:bg-zinc-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 transition">
      Me contacter
    </button>
  </div>
</section>

Le bouton « Me contacter » du palier 1 : fond noir, texte clair, coins arrondis en pilule

Maintenant, trois manipulations. Fais-les une par une, regarde le navigateur entre chaque, puis remets la classe d'origine avant de passer à la suivante.

  1. Remplace bg-zinc-900 par bg-amber-300. Le bouton devient jaune… et le texte text-stone-50 devient presque illisible. C'est un problème de contraste. Corrige en mettant aussi text-zinc-900.
  2. Supprime rounded-full. Le bouton devient un rectangle à angles droits. Essaie ensuite rounded-md, puis rounded-none. Trois personnalités très différentes pour une seule classe.
  3. Supprime transition. Survole le bouton : le changement de couleur devient brutal, instantané. Remets-la.

Note

Prends l'habitude de cette boucle : je change une classe, je regarde, je comprends, je passe à la suivante. Changer cinq classes d'un coup et se demander laquelle a fait quoi, c'est comme ça qu'on perd une heure.

Palier 2 — Complète les trous

Colle ce deuxième bouton dans le même <div class="flex flex-wrap gap-4">. Remplace chaque ??? par une classe. Le commentaire juste au-dessus te dit ce qu'on attend et te propose trois candidates : choisis-en une.

<button class="
  ??? ??? ??? ??? ??? ??? ??? ???
">
  Voir mes projets
</button>

Voici les huit trous, dans l'ordre :

<!-- ??? couleur de fond : bg-amber-300 | bg-emerald-400 | bg-orange-500 -->
<!-- ??? couleur du texte, qui doit contraster avec le fond choisi : text-zinc-900 | text-white | text-stone-50 -->
<!-- ??? padding intérieur, généreux : px-6 py-3 | px-8 py-4 | px-4 py-2 -->
<!-- ??? bordure épaisse et noire : border-2 border-zinc-900 | border-4 border-zinc-900 | border-8 border-zinc-900 -->
<!-- ??? arrondi : rounded-none | rounded-sm | rounded-md -->
<!-- ??? ombre dure et décalée : shadow-[4px_4px_0_0_#18181b] | shadow-[6px_6px_0_0_#18181b] | shadow-lg -->
<!-- ??? effet au survol : hover:-translate-y-0.5 | hover:bg-zinc-900 | hover:rotate-1 -->
<!-- ??? focus clavier visible : focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 | focus-visible:ring-2 focus-visible:ring-zinc-900 | focus-visible:ring-4 focus-visible:ring-amber-300 -->

Objectif : un bouton brutaliste — couleur franche, bordure noire épaisse, angles droits ou presque, ombre dure. Pas de flou, pas de dégradé.

Teste avec la touche [TAB] : ton bouton doit montrer clairement qu'il a le focus.

Une combinaison parmi d'autres :

<button class="bg-amber-300 text-zinc-900 px-6 py-3 border-4 border-zinc-900 rounded-none shadow-[4px_4px_0_0_#18181b] font-extrabold uppercase tracking-wide hover:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 transition">
  Voir mes projets
</button>

Le bouton brutaliste rendu : fond jaune, bordure noire épaisse, angles droits et ombre dure décalée

Une autre, tout aussi valable, plus sourde :

<button class="bg-emerald-400 text-zinc-900 px-8 py-4 border-2 border-zinc-900 rounded-sm shadow-[6px_6px_0_0_#18181b] font-bold hover:bg-zinc-900 hover:text-emerald-400 focus-visible:ring-2 focus-visible:ring-zinc-900 transition">
  Voir mes projets
</button>

Palier 3 — À toi

Consigne : ajoute trois boutons de plus, chacun dans une direction esthétique différente, choisie dans cette liste :

  • éditorial : serif, fin, beaucoup d'air, peu de couleur ;
  • riso / imprimé : une couleur franche, une bordure épaisse, aucun effet de profondeur ;
  • minimal japonais : blanc cassé, trait fin, une seule respiration ;
  • brutaliste : contrastes violents, majuscules, ombre dure ;
  • ticket de caisse : monospace, majuscules, bordure pointillée.

Trois directions différentes : pas trois variantes de la même. Le but est que le prof puisse deviner ta direction sans que tu la nommes.

Attention

Interdits, et ce n'est pas négociable : néon / cyberpunk, glassmorphism (backdrop-blur + fond blanc translucide), dégradés violet-rose. C'est le slop du chapitre d'intro : le réglage par défaut de tous les générateurs, donc l'absence de décision. Tu peux le faire pour rire chez toi, pas ici.

Banque de classes — pioche, combine, cherche le reste dans la doc.

Catégorie Classes
Fond bg-white, bg-stone-100, bg-zinc-900, bg-amber-300, bg-red-600, bg-emerald-500, bg-blue-700, bg-transparent
Texte text-zinc-900, text-zinc-600, text-white, text-stone-50, font-serif, font-mono, font-light, font-bold, font-extrabold, uppercase, tracking-tight, tracking-widest, text-sm, text-lg
Espacement px-3 py-1.5, px-5 py-2.5, px-8 py-4, gap-4
Bordure border, border-2, border-4, border-zinc-900, border-zinc-300, border-dashed, border-dotted, rounded-none, rounded-md, rounded-full
États hover:bg-zinc-700, hover:text-white, hover:-translate-y-0.5, active:scale-95, focus-visible:outline-2 focus-visible:outline-offset-2, focus-visible:ring-2, transition
Ombre shadow-xs, shadow-sm, shadow-lg, shadow-none, shadow-[4px_4px_0_0_#18181b]

Critères observables

  • Trois boutons, trois directions esthétiques nettement distinctes
  • Chacun a un hover: visible
  • Chacun a un focus clavier visible, testé au [TAB]
  • Le texte contraste franchement avec son fond
  • Aucun néon, aucun glassmorphism, aucun dégradé violet-rose
  • Pas de classes inutiles empilées « au cas où »

Montre au prof cette checklist cochée et tes cinq boutons à l'écran.

Exercice 2 — Carte de profil

Durée indicative : 45 minutes.

C'est la future carte « à propos » de ton portfolio. Autant la faire te ressembler tout de suite.

Palier 2 — Complète les trous

Colle cette section. La structure est donnée, les décisions de style sont à toi.

<section class="mb-12">
  <h2 class="text-2xl font-bold text-zinc-900 mb-4">Carte de profil</h2>

  <!-- ??? ombre de la carte au repos : shadow-xs | shadow-sm | shadow-lg -->
  <!-- ??? effet au survol de toute la carte : hover:shadow-xl | hover:-translate-y-1 | hover:border-zinc-900 -->
  <article class="max-w-sm bg-white border border-zinc-200 overflow-hidden ??? ??? transition">

    <!-- ??? hauteur de l'image : h-40 | h-48 | h-64 -->
    <!-- ??? cadrage de l'image, pour qu'elle ne soit pas déformée : object-cover | object-contain | object-fill -->
    <img
      src="https://i.pravatar.cc/600"
      alt="Portrait"
      class="w-full ??? ???"
    >

    <!-- ??? padding intérieur du bloc texte : p-4 | p-6 | p-8 -->
    <div class="???">

      <!-- ??? taille et graisse du nom : text-xl font-bold | text-2xl font-bold | text-2xl font-serif -->
      <h3 class="text-zinc-900 ???">Prénom Nom</h3>

      <!-- ??? style du sous-titre, plus discret que le nom : text-sm text-zinc-500 | text-base text-zinc-600 | text-xs uppercase tracking-widest text-zinc-500 -->
      <p class="mt-1 ???">Webdesign &amp; développement</p>

      <!-- ??? espace au-dessus de la bio : mt-2 | mt-4 | mt-6 -->
      <p class="??? text-zinc-600 leading-relaxed">
        Une ou deux phrases sur toi. Ce que tu fais, ce que tu cherches.
      </p>

      <!-- ??? bouton : reprends les classes d'un de tes boutons de l'exercice 1 -->
      <button class="mt-6 ???">
        Me contacter
      </button>
    </div>
  </article>
</section>
<article class="max-w-sm bg-white border border-zinc-200 overflow-hidden shadow-sm hover:shadow-xl transition">
  <img
    src="https://i.pravatar.cc/600"
    alt="Portrait"
    class="w-full h-48 object-cover"
  >
  <div class="p-6">
    <h3 class="text-zinc-900 text-2xl font-bold">Prénom Nom</h3>
    <p class="mt-1 text-xs uppercase tracking-widest text-zinc-500">Webdesign &amp; développement</p>
    <p class="mt-4 text-zinc-600 leading-relaxed">
      Une ou deux phrases sur toi. Ce que tu fais, ce que tu cherches.
    </p>
    <button class="mt-6 bg-zinc-900 text-stone-50 px-5 py-2.5 rounded-full font-medium hover:bg-zinc-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 transition">
      Me contacter
    </button>
  </div>
</article>

La carte de profil corrigée : image en haut, puis nom, sous-titre, bio et bouton « Me contacter »

object-cover recadre l'image pour remplir la zone sans la déformer ; object-contain laisse des bandes vides ; object-fill l'écrase. Pour un portrait, c'est object-cover.

Palier 3 — À toi

Consigne : refais cette carte dans ta direction — celle que tu as choisie à l'exercice 1. Même contenu, autre parti pris. Tu peux déplacer l'image, la supprimer, passer en deux colonnes, mettre le nom en énorme, ne garder qu'un trait.

Remplace le texte d'exemple par le tien : ton vrai prénom, ta vraie phrase. C'est la carte qui ira sur ton portfolio.

Banque de classes

Catégorie Classes
Fond bg-white, bg-stone-100, bg-amber-100, bg-zinc-900
Texte font-serif, font-mono, text-sm, text-2xl, text-4xl, font-light, font-black, leading-relaxed, tracking-tight
Espacement p-4, p-8, mt-2, mt-6, space-y-3, max-w-sm, max-w-md
Bordure border, border-2, border-zinc-900, border-b, rounded-none, rounded-lg, overflow-hidden
Image w-full, h-40, h-64, object-cover, aspect-square, rounded-full, grayscale
États hover:shadow-xl, hover:-translate-y-1, transition, focus-visible:ring-2
Responsive md:flex, md:w-1/2, md:text-3xl, md:p-10

Critères observables

  • Le contenu est le mien, pas le texte d'exemple
  • La hiérarchie est claire : on lit le nom en premier, la bio en dernier
  • L'image n'est pas déformée
  • La carte réagit au survol
  • Le bouton a un focus clavier visible
  • La direction esthétique est la même qu'à l'exercice 1

Montre au prof la carte et la checklist.

Exercice 3 — Navbar responsive

Durée indicative : 30 minutes.

Palier 1 — Copie et observe

Cette navbar se place avant le <h1>, tout en haut du <main> — ou mieux, juste au-dessus, collée en haut de page.

<nav class="bg-white border-b-2 border-zinc-900 px-6 py-4 mb-10">
  <div class="mx-auto max-w-5xl flex items-center justify-between">
    <span class="text-xl font-bold tracking-tight text-zinc-900">MonSite</span>

    <div class="hidden md:flex gap-8">
      <a href="#" class="text-zinc-700 hover:text-zinc-900 transition">Accueil</a>
      <a href="#" class="text-zinc-700 hover:text-zinc-900 transition">Projets</a>
      <a href="#" class="text-zinc-700 hover:text-zinc-900 transition">Contact</a>
    </div>

    <button class="md:hidden text-2xl text-zinc-900" aria-label="Ouvrir le menu">
      &#9776;
    </button>
  </div>
</nav>

La navbar du palier 1 sur écran large : logo « MONSITE » à gauche, liens Accueil/Projets/Contact à droite, bordure basse jaune

Trois manipulations :

  1. Ouvre les DevTools (F12 sur Windows, Cmd + Option + I sur Mac), active le mode responsive (l'icône téléphone/tablette, ou Ctrl + Shift + M / Cmd + Option + M). Fais varier la largeur autour de 768 px : les liens disparaissent, le bouton hamburger apparaît. C'est hidden md:flex d'un côté et md:hidden de l'autre.
  2. Remplace hidden md:flex par flex. Les liens restent visibles même en mobile, et ça déborde. Remets la version d'origine.
  3. Remplace md: par lg: partout (trois endroits). Le basculement se fait maintenant à 1024 px au lieu de 768.

Note

Le bouton hamburger ne fait rien pour l'instant : il n'y a pas de JavaScript. C'est normal, on le branchera quand on verra la réactivité de Vue.

Palier 2 — Complète les trous

Repars de la navbar ci-dessus et remplace ces classes par tes choix.

<!-- ??? fond de la navbar : bg-white | bg-stone-100 | bg-zinc-900 -->
<!-- ??? bordure basse : border-b border-zinc-200 | border-b-2 border-zinc-900 | border-b-4 border-amber-300 -->
<nav class="??? ??? px-6 py-4 mb-10">
  <div class="mx-auto max-w-5xl flex items-center justify-between">

    <!-- ??? taille du logo : text-lg | text-xl | text-2xl -->
    <!-- ??? caractère du logo : font-bold tracking-tight | font-serif | font-mono uppercase tracking-widest -->
    <span class="??? ??? text-zinc-900">MonSite</span>

    <!-- ??? espacement entre les liens : gap-4 | gap-8 | gap-12 -->
    <div class="hidden md:flex ???">

      <!-- ??? survol des liens : hover:text-zinc-900 | hover:underline hover:underline-offset-4 | hover:bg-amber-300 -->
      <a href="#" class="text-zinc-700 ??? transition">Accueil</a>
      <a href="#" class="text-zinc-700 ??? transition">Projets</a>
      <a href="#" class="text-zinc-700 ??? transition">Contact</a>
    </div>

    <button class="md:hidden text-2xl text-zinc-900" aria-label="Ouvrir le menu">
      &#9776;
    </button>
  </div>
</nav>
<nav class="bg-stone-100 border-b-4 border-amber-300 px-6 py-4 mb-10">
  <div class="mx-auto max-w-5xl flex items-center justify-between">
    <span class="text-2xl font-mono uppercase tracking-widest text-zinc-900">MonSite</span>

    <div class="hidden md:flex gap-8">
      <a href="#" class="text-zinc-700 hover:underline hover:underline-offset-4 transition">Accueil</a>
      <a href="#" class="text-zinc-700 hover:underline hover:underline-offset-4 transition">Projets</a>
      <a href="#" class="text-zinc-700 hover:underline hover:underline-offset-4 transition">Contact</a>
    </div>

    <button class="md:hidden text-2xl text-zinc-900" aria-label="Ouvrir le menu">
      &#9776;
    </button>
  </div>
</nav>

La navbar corrigée à 390 px de large : les liens sont masqués, le bouton hamburger apparaît

Si tu choisis bg-zinc-900, pense à repasser le logo et les liens en clair : text-stone-50, text-zinc-300. Sinon, contraste raté.

Critères observables

  • En dessous de 768 px : liens cachés, hamburger visible
  • Au-dessus : liens visibles, hamburger caché
  • Les liens réagissent au survol
  • Logo et liens lisibles sur le fond choisi
  • La navbar ne déborde pas horizontalement en mobile

Montre au prof le basculement en direct dans les DevTools.

Exercice 4 — Formulaire de contact

Durée indicative : 40 minutes.

Palier 2 — Complète les trous

La structure HTML est complète, y compris les for / id qui associent chaque label à son champ. Tu ne touches qu'aux classes.

<section class="mb-12">
  <h2 class="text-2xl font-bold text-zinc-900 mb-4">Me contacter</h2>

  <!-- ??? fond et cadre du bloc : bg-white border border-zinc-200 | bg-white border-2 border-zinc-900 | bg-stone-50 border-none -->
  <!-- ??? padding du bloc : p-6 | p-8 | p-10 -->
  <form class="max-w-md ??? ??? space-y-5">

    <div>
      <!-- ??? style des labels : text-sm font-medium text-zinc-700 | text-xs uppercase tracking-widest text-zinc-500 | text-base font-bold text-zinc-900 -->
      <label for="nom" class="block mb-1.5 ???">Nom complet</label>

      <!-- ??? bordure du champ au repos : border border-zinc-300 | border-2 border-zinc-900 | border-b-2 border-zinc-400 -->
      <!-- ??? focus clavier visible : focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 | focus-visible:ring-2 focus-visible:ring-zinc-900 | focus-visible:border-zinc-900 focus-visible:bg-amber-50 -->
      <input
        id="nom"
        type="text"
        placeholder="Prénom Nom"
        class="w-full px-4 py-2.5 rounded-md placeholder:text-zinc-400 ??? ???"
      >
    </div>

    <div>
      <label for="email" class="block mb-1.5 ???">Email</label>
      <input
        id="email"
        type="email"
        placeholder="prenom@exemple.be"
        class="w-full px-4 py-2.5 rounded-md placeholder:text-zinc-400 ??? ???"
      >
    </div>

    <div>
      <label for="message" class="block mb-1.5 ???">Message</label>

      <!-- ??? mêmes bordure et focus que les champs ci-dessus, pour rester cohérent -->
      <textarea
        id="message"
        rows="4"
        placeholder="Ton message"
        class="w-full px-4 py-2.5 rounded-md placeholder:text-zinc-400 ??? ???"
      ></textarea>
    </div>

    <!-- ??? bouton d'envoi, pleine largeur : w-full bg-zinc-900 text-stone-50 | w-full bg-red-600 text-white | w-full bg-amber-300 text-zinc-900 border-2 border-zinc-900 -->
    <!-- ??? survol du bouton : hover:bg-zinc-700 | hover:opacity-90 | hover:-translate-y-0.5 -->
    <button
      type="submit"
      class="??? px-6 py-3 rounded-md font-medium ??? focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 transition"
    >
      Envoyer
    </button>
  </form>
</section>
<form class="max-w-md bg-white border-2 border-zinc-900 p-8 space-y-5">
  <div>
    <label for="nom" class="block mb-1.5 text-xs uppercase tracking-widest text-zinc-500">Nom complet</label>
    <input
      id="nom"
      type="text"
      placeholder="Prénom Nom"
      class="w-full px-4 py-2.5 rounded-md placeholder:text-zinc-400 border border-zinc-300 focus-visible:ring-2 focus-visible:ring-zinc-900"
    >
  </div>
  <!-- email et message sur le même modèle -->
  <button
    type="submit"
    class="w-full bg-amber-300 text-zinc-900 border-2 border-zinc-900 px-6 py-3 rounded-md font-medium hover:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 transition"
  >
    Envoyer
  </button>
</form>

Le formulaire corrigé : champs Nom complet, Email et Message avec leurs labels, et un bouton « Envoyer » jaune pleine largeur

Les trois champs doivent recevoir les mêmes classes de bordure et de focus : un formulaire où chaque champ réagit différemment donne l'impression que la page est cassée.

Checklist accessibilité

Celle-ci, on la vérifie ensemble, champ par champ.

  • Chaque champ a un <label> avec un for qui correspond exactement à son id
  • Je clique sur le texte du label : le curseur saute dans le champ (c'est le test qui prouve que l'association marche)
  • Je parcours tout le formulaire au [TAB] : à chaque étape, je vois où je suis
  • Le focus est visible sur les trois champs et sur le bouton
  • Le texte des labels contraste franchement avec le fond (pas de text-zinc-400 sur blanc)
  • Le placeholder ne remplace pas le label : il donne un exemple, il ne dit pas ce qu'on demande
  • Les trois champs ont le même traitement visuel

Montre au prof le parcours complet au clavier, sans toucher la souris.

Exercice 5 — Grille de projets

Durée indicative : 45 minutes.

C'est la future grille de projets de ton portfolio.

Palier 1 — Copie et observe

Voici une carte. Tu la colles dans la grille, puis tu la dupliques cinq fois de plus (copier-coller) pour en avoir six, en changeant le ?random=1 en 2, 3… et le titre de chaque projet.

<section class="mb-12">
  <h2 class="text-2xl font-bold text-zinc-900 mb-4">Mes projets</h2>

  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">

    <article class="bg-white border border-zinc-200 overflow-hidden hover:shadow-lg transition">
      <img
        src="https://picsum.photos/600/400?random=1"
        alt="Aperçu du projet 1"
        class="w-full h-48 object-cover"
      >
      <div class="p-5">
        <h3 class="text-lg font-bold text-zinc-900">Projet 1</h3>
        <p class="mt-2 text-sm text-zinc-600 leading-relaxed">
          Une phrase qui dit ce que c'est et pour qui.
        </p>
        <span class="mt-4 inline-block text-xs uppercase tracking-widest text-zinc-500">
          Design
        </span>
      </div>
    </article>

    <!-- Duplique cet <article> cinq fois de plus -->

  </div>
</section>

La grille de six cartes de projets sur trois colonnes, chacune avec une image, un titre « Projet », une phrase et une étiquette de catégorie

Deux manipulations :

  1. Ouvre les DevTools en mode responsive et fais varier la largeur : 1 colonne en mobile, 2 dès 768 px (md:grid-cols-2), 3 dès 1024 px (lg:grid-cols-3). Change lg:grid-cols-3 en lg:grid-cols-4 et observe.
  2. Supprime object-cover sur une seule carte et compare-la à ses voisines : l'image est écrasée. C'est à ça que sert cette classe.

Palier 3 — À toi

Consigne : redessine cette carte dans la direction que tu as choisie à l'exercice 1. Une seule carte à concevoir, puis tu répercutes sur les six (copier-coller). Tu peux tout changer : supprimer l'image, la mettre en noir et blanc, passer le titre en énorme, mettre le tag en tampon coloré, retirer les bordures, inverser les couleurs.

Remplace les faux titres par tes vrais projets — même s'ils ne sont pas encore faits : les projets de l'année, un travail de l'an dernier, une envie. Tu réécriras plus tard, mais du texte réel donne un vrai design.

Banque de classes

Catégorie Classes
Fond bg-white, bg-stone-100, bg-zinc-900, bg-amber-100, bg-blue-700
Texte text-lg, text-2xl, font-serif, font-mono, font-black, uppercase, tracking-widest, text-zinc-600, text-stone-50, line-clamp-2
Espacement p-4, p-6, gap-2, gap-6, gap-10, mt-2, mt-4
Bordure border, border-2, border-zinc-900, border-t-4, rounded-none, rounded-lg, overflow-hidden
Image h-40, h-56, object-cover, aspect-video, aspect-square, grayscale, hover:grayscale-0
États hover:shadow-lg, hover:-translate-y-1, hover:bg-amber-300, transition, focus-visible:ring-2
Responsive grid-cols-1, sm:grid-cols-2, md:grid-cols-2, lg:grid-cols-3, md:gap-8

Critères observables

  • Six cartes, toutes traitées exactement pareil
  • La grille passe de 1 à 2 à 3 colonnes selon la largeur
  • Les images ne sont pas déformées
  • Les titres sont mes vrais projets, pas « Projet 1 »
  • La carte réagit au survol
  • La direction esthétique est la même que celle des exercices 1 et 2
  • Aucun néon, aucun glassmorphism, aucun dégradé violet-rose

Montre au prof la grille en mode responsive et la checklist.

Chercher par soi-même

Dans la doc Tailwind

  1. Va sur tailwindcss.com/docs.
  2. Utilise la barre de recherche (Ctrl + K sur Windows, Cmd + K sur Mac), en anglais et par propriété CSS, pas par intention : cherche border-radius plutôt que « coins arrondis », object-fit plutôt que « image pas déformée ».
  3. Chaque page liste toutes les classes de la famille avec leur équivalent CSS. Quand tu as le CSS en tête, tu as la classe.

Attention

Une recherche Google te renverra souvent vers des articles écrits pour Tailwind v3. Les signes qui trahissent : un tailwind.config.js, bg-gradient-to-r (v4 : bg-linear-to-r), flex-shrink-0 (v4 : shrink-0). En cas de doute, la doc officielle fait foi.

Demander à une IA sans se faire refiler du slop

Une IA à qui tu ne donnes pas de direction te rendra la moyenne d'Internet : dégradé violet-rose, coins arrondis, ombre floue, glassmorphism. Ce n'est pas la faute du modèle, c'est la tienne : tu n'as rien décidé, donc elle décide à ta place, et elle décide comme tout le monde.

Mauvais prompt

Fais-moi un bouton stylé en Tailwind.

Bon prompt

Écris le template d'un bouton en Tailwind CSS v4, classes uniquement, pas de CSS custom. Direction : imprimé riso — un aplat de couleur franche, une bordure noire de 2 px, angles droits, aucune ombre floue. Palette : fond crème stone-100, encre zinc-900, accent amber-300. Contraintes : focus clavier visible avec focus-visible:, contraste texte/fond d'au moins 4,5:1, maximum 10 classes. Interdits : dégradés, backdrop-blur, néon, shadow-xl. Donne-moi trois variantes qui diffèrent vraiment, pas trois nuances de la même.

La différence tient en quatre choses : une direction nommée, une palette imposée, des contraintes vérifiables, des interdits explicites. Et surtout : tu dois pouvoir dire pourquoi tu gardes le résultat. Si tu ne peux pas, rebriefe.

Astuce

Demande toujours de courtes réponses et relis chaque classe. Une IA invente des classes qui n'existent pas (c'est arrivé à ton prof avec shadow-brutalist). L'autocomplétion de VS Code est ton filtre : une classe qui n'apparaît pas dans la liste n'existe pas.

Récap

  • Palier 1 : on copie, on modifie une classe à la fois, on regarde.
  • Palier 2 : on choisit parmi des candidates — plusieurs réponses sont justes, c'est l'intention qui tranche.
  • Palier 3 : on conçoit, avec des critères observables et une banque de classes.
  • Une direction esthétique tenue sur les exercices 1, 2 et 5 : c'est déjà l'identité de ton portfolio.
  • Focus visible et contraste sur chaque exercice. Ce n'est pas du bonus.
  • Cherche par propriété CSS dans la doc v4 ; brief une IA avec direction, palette, contraintes et interdits.