# 🛠️ Page Services — relecture & prochaine étape Salut Guillaume ! 👋 Ta page services avance super bien : le tableau des prestations est clair, les boutons de navigation sont stylés, et tu as même ajouté une petite icône SVG sur le bouton « retour ». Bravo, c'est du bon travail ! 🎉 Ce guide a deux objectifs : 1. Te montrer **3 bugs** à corriger (avec l'explication, pas juste la solution). 2. T'apprendre à **définir et limiter une ` ``` Le problème : tu **ouvres** `
` puis tu le **refermes** (`
`) tout de suite, juste après la phrase d'intro. Du coup, tous tes champs (``, `
``` > 💡 **À retenir :** un `
` est une **boîte**. Tout ce qu'on veut envoyer (champs + bouton « Envoyer ») doit être **dedans**, entre `` et `
`. --- ## 🐛 Bug 2 — Un dégradé qui ne s'affiche pas (parenthèses oubliées) Dans `style_services.css`, ton bouton de la page courante `.x_to_x` : ```css .x_to_x { background-image: linear-gradient to top left, /* ❌ il manque les parenthèses */ rgb(0 0 0 / 0.2), rgb(0 0 0 / 0.2) 30%, transparent; } ``` `linear-gradient` est une **fonction** : comme en maths, ses arguments vont **entre parenthèses**. Sans elles, le navigateur ne comprend pas la ligne et **ignore tout le dégradé**. C'est pour ça que ce bouton n'a pas le même rendu que les autres. ### ✅ Correction (compare avec ta classe `.styled` qui, elle, est correcte) ```css .x_to_x { background-image: linear-gradient( to top left, rgb(0 0 0 / 0.2), rgb(0 0 0 / 0.2) 30%, transparent ); } ``` > 💡 **À retenir :** `linear-gradient( … )`, `rgb( … )`, `calc( … )` … toutes les **fonctions** CSS prennent leurs arguments **entre parenthèses**. Une fonction sans parenthèses = ligne ignorée. --- ## 🎯 Bug 3 — L'icône SVG n'est pas centrée dans le bouton « retour » Ton bouton mélange une **image** (le SVG) et du **texte** côte à côte : ```html ``` Le souci : par défaut, une icône SVG se pose **sur la ligne du texte** (sur la « ligne de base », comme une lettre). Du coup elle paraît trop haute ou trop basse, et ton `line-height: 2.5` accentue le décalage. L'icône et le mot « retour » ne sont pas alignés sur leur **milieu**. ### ✅ La solution : transformer le bouton en boîte flex ```css .retour { display: inline-flex; /* le bouton range ses enfants (icône + texte) */ align-items: center; /* ↕ les centre verticalement, sur le même milieu */ justify-content: center; /* ↔ les centre horizontalement */ gap: 6px; /* un petit espace entre l'icône et le mot */ line-height: normal; /* on enlève le 2.5 qui déréglait l'alignement */ /* ...garde le reste de tes styles (couleur, border-radius, etc.) */ } ``` `align-items: center`, c'est **exactement** le `flex` que tu connais déjà (tu l'utilises sur `#buttons` et `.align_x`). Ici on l'applique **au bouton lui-même**, parce que c'est lui le parent qui contient l'icône **et** le texte. > 💡 **À retenir :** dès qu'un bouton (ou n'importe quelle boîte) contient **une icône + du texte** à aligner, passe-le en `display: inline-flex; align-items: center;`. C'est le réflexe pro pour centrer proprement une icône avec du texte. > ⚠️ **Ça vaut aussi pour ton nouveau bouton « Envoyer le message »** : tu viens d'y ajouter l'icône SVG « avion en papier », il a donc exactement le même décalage. Applique-lui la même recette flex (par ex. une classe commune `.btn-icone` que tu mets sur les deux boutons, plutôt que de répéter le CSS). --- ## 📐 La leçon du jour : définir et **limiter** une ` ``` Par défaut elle est petite, et surtout l'utilisateur peut écrire **un roman de 10 000 mots** sans aucune limite. On va apprendre à la **cadrer**. ### 1️⃣ Lui donner une taille de départ : `rows` et `cols` ```html ``` - `rows` = nombre de **lignes** visibles (la hauteur). - `cols` = nombre de **colonnes** = caractères en largeur. > 🔎 `rows`/`cols` ne sont **pas** des pixels : c'est « combien de lignes/caractères je vois ». C'est la taille **de départ**. ### 2️⃣ Limiter le nombre de caractères : `maxlength` ```html ``` `maxlength="500"` = l'utilisateur **ne peut pas** taper plus de 500 caractères. C'est le navigateur qui bloque tout seul, sans JavaScript. 👍 ### 3️⃣ Empêcher (ou cadrer) le redimensionnement : `resize` en CSS Tu as remarqué la petite poignée en bas à droite d'une textarea ? L'utilisateur peut l'étirer et **casser ta mise en page**. On contrôle ça en CSS : ```css #msg { resize: vertical; /* il peut agrandir en hauteur seulement (recommandé) */ /* resize: none; pour interdire complètement le redimensionnement */ width: 100%; /* la largeur, on la pilote en CSS, pas avec cols */ min-height: 120px; } ``` > 💡 **À retenir :** > - `rows` / `cols` → **taille de départ** (lignes / caractères). > - `maxlength` → **limite** le nombre de caractères (le navigateur bloque tout seul). > - `resize` (CSS) → contrôle la **poignée** d'étirement (`vertical`, `horizontal`, `none`, `both`). > - Astuce de pro : on règle souvent la **largeur en CSS** (`width`) et on garde `rows` pour la hauteur de départ. ### 4️⃣ 👉 Votre question : laisser l'utilisateur redimensionner, mais **entre un min et un max** Tu as choisi pour l'instant : ```css #msg { resize: none; /* la poignée est désactivée : l'utilisateur ne peut RIEN étirer */ width: 200px; } ``` `resize: none` est un **choix valable** (la zone est verrouillée). Mais vous m'avez demandé l'inverse : **autoriser** l'agrandissement, tout en **empêchant que ça parte trop grand ou trop petit**. La recette tient en 2 idées qui se combinent : 1. **`resize`** dit *dans quelle direction* on peut étirer. 2. **`min-*` / `max-*`** disent *jusqu'où* on peut aller. ```css #msg { resize: vertical; /* on autorise l'étirement, mais en HAUTEUR seulement */ min-height: 80px; /* impossible de la réduire en dessous de 80px */ max-height: 300px; /* impossible de l'agrandir au-delà de 300px */ width: 100%; /* largeur pilotée en CSS, pas par l'utilisateur */ } ``` Avec ça : l'utilisateur attrape la poignée, tire vers le bas pour avoir plus de place… mais **la zone refuse de dépasser 300px** et **de descendre sous 80px**. Ta mise en page reste protégée. 🎉 #### Et si on veut autoriser les **deux** sens (vertical **et** horizontal) ? Même principe, mais avec **4 bornes** : 2 pour la hauteur, 2 pour la largeur. On passe `resize` à `both` : ```css #msg { resize: both; /* la poignée étire en hauteur ET en largeur */ min-height: 80px; /* bornes verticales */ max-height: 300px; min-width: 200px; /* bornes horizontales */ max-width: 100%; /* ne dépasse jamais la largeur du parent → pas de scroll */ } ``` Chaque direction a sa paire `min`/`max` : - **hauteur** → `min-height` / `max-height` - **largeur** → `min-width` / `max-width` L'utilisateur peut alors étirer dans tous les sens, mais **jamais au-delà** de ces 4 limites. > ⚠️ Le piège classique en horizontal : mets `max-width: 100%` (et pas une grande valeur en `px`), sinon l'utilisateur peut élargir la zone **plus que l'écran** et faire réapparaître la barre de défilement horizontale (souviens-toi du bug du scroll 😉). Récap des valeurs de `resize` : | `resize` | Ce que l'utilisateur peut étirer | |---|---| | `none` | rien (verrouillé) — ton choix actuel | | `vertical` | la hauteur seulement (le plus confortable pour un message) | | `horizontal` | la largeur seulement | | `both` | les deux | > 💡 **À retenir :** `resize` = **la direction** autorisée. `min-height`/`max-height` (et `min-width`/`max-width`) = **les bornes**. Les deux ensemble = un redimensionnement libre **mais encadré**. --- ## 🚀 Ta première mission JavaScript : le **simulateur de devis FleetZen** Jusqu'ici tu as fait du HTML (la **structure**) et du CSS (l'**apparence**). Le JavaScript, c'est la **3ᵉ couche** : le **comportement**, ce qui réagit quand on clique. 🧠 On va le faire **en mode tuto** : tu construis petit bout par petit bout, et **tu testes à chaque étape**. Ne copie pas tout d'un coup — avance palier par palier, c'est comme ça qu'on comprend. 🙂 **Objectif final :** un petit **simulateur** où le client choisit **combien de véhicules** il a, et le prix total se met à jour **tout seul**, sans recharger la page. --- ### 🪜 Étape 0 — Découvrir la console (ton meilleur ami) Avant tout : ouvre ta page dans le navigateur, puis appuie sur **F12** → onglet **Console**. C'est là que le JS « parle ». Crée un fichier `css/devis.js` avec une seule ligne : ```js console.log("Mon fichier JS est bien chargé !"); ``` Et branche-le en bas du ``, **juste avant** `` : ```html ``` > 🔎 Pourquoi à la fin du body ? Parce que le JS s'exécute de haut en bas. S'il se lance **avant** que le HTML existe, il ne trouve rien à manipuler. À la fin, tout le HTML est déjà là. 👍 **✅ Teste maintenant :** recharge la page. Tu dois voir ton message dans la Console. Si oui, ton JS est branché. Sinon, vérifie le chemin du `src`. --- ### 🪜 Étape 1 — Ajouter le HTML du simulateur Sous ton tableau, ajoute : ```html

Estimez votre devis

Nombre de véhicules dans votre flotte :

1

Total géolocalisation : 30 €/mois

``` **✅ Teste maintenant :** tu dois voir les boutons `−` et `+` et le chiffre `1`. Pour l'instant ils ne font rien, c'est normal : on n'a pas encore écrit le comportement. > 🔎 Remarque les **`id`** (`moins`, `plus`, `nb_vehicules`, `total`). Un `id` est une **étiquette unique** : c'est par là que le JS va « attraper » chaque élément à l'étape suivante. --- ### 🪜 Étape 2 — Attraper les éléments depuis le JS Dans `devis.js`, remplace ton `console.log` de test par : ```js // "Attraper" un élément du HTML grâce à son id const boutonPlus = document.getElementById("plus"); console.log(boutonPlus); // pour vérifier qu'on l'a bien trouvé ``` **✅ Teste maintenant :** dans la Console tu dois voir s'afficher ton ` `; } // On l'injecte tout en haut du body : document.body.insertAdjacentHTML("afterbegin", creerNavbar()); ``` **✅ Teste :** enlève la navbar écrite « en dur » dans le HTML, garde ce JS, recharge → la navbar réapparaît, générée par la fonction. Maintenant le jour où tu changes un lien, tu le changes **à un seul endroit** pour **toutes** les pages. > 💡 **À retenir :** un **composant** = un bout d'interface écrit **une fois** et **réutilisé** partout. C'est l'idée centrale derrière React, Vue, etc. — mais ça commence par une simple fonction comme celle-ci. --- ## ✅ Ta checklist - [ ] Remettre tous les champs **dans** le `
` (Bug 1) - [ ] Réparer le dégradé de `.x_to_x` avec les parenthèses (Bug 2) - [ ] Centrer l'icône SVG des boutons « retour » **et** « Envoyer » avec `inline-flex` (Bug 3) - [ ] Ajouter `rows`, `maxlength` + redimensionnement borné (`resize: vertical` + `min/max-height`) - [ ] Faire marcher le **simulateur de devis** en JavaScript - [ ] (Bonus) Transformer la navbar en composant réutilisable - [ ] Commits petits et clairs, puis `git push` Pose-moi toutes tes questions. Tu gères ! 🚗💨