Booki (Page d'accueil d'une agence de voyage)
Sommaire
Mes projets réalisés en formation chez OpenClassrooms - Cet article fait partie d'une série.
Tout premier projet du parcours de développeur web d’Open Classrooms, Booki consiste en l’intégration de maquettes Figma (version mobile, tablette et PC).
C’est l’occasion parfaite de commencer à créer des pages web et apprendre des notions comme le HTML sémantique, ou encore les variables et sélecteurs CSS !
Booki #
Résultat du projet #
Page web #
Cliquez sur le bouton ci-dessous pour découvrir la page web que j'ai réalisée et accédez-y dès maintenant !
👉 Lancer la démo !
Code source (GitHub) #
HTML/CSS project made during an OpenClassrooms bootcamp
Pistes pour la réalisation du projet #
Il s’agit d’un condensé des réflexions que je me suis faites.
Vous ne comprenez pas un point dans cet article ? 🤔
Vous venez d’identifier une de vos lacunes (et c’est une bonne chose).
Dans ce cas : travaillez les ressources fournies avant de poursuivre.
Afin de réaliser ce projet, il m’a fallu expérimenter en HTML et en CSS.
Cela a comporté son lot d’essais et de surprises, et donc de choix à partager.
🔗 Maquettes Figma de Booki (PC, tablette, mobile)
Bien commencer #
⬇ Vous trouverez en annexe une sélection de ressources pédagogiques
Avant de se lancer… (HTML) #
Comme vous le constaterez, l’indentation (espaces en début de ligne) est un sujet qui revient en permanence avec le HTML.
Pour ce projet, vous n’aurez pas besoin d’extensions particulières dans votre éditeur de code.
Je vous recommande juste de vous assurer que votre formatter fonctionne correctement afin de pouvoir rapidement indenter automatiquement votre code.
CTRL+Shift+P
*, puis appelez la commande Format Document
.* Le raccourci clavier sera
Cmd+Shift+P
sur Mac.Et si vous souhaitez utiliser un autre formatter que celui de VSCode…
🔗 Ma configuration Prettier
Vous pouvez également vous épauler d’une IA :
- 🔗 ChatGPT,
- 🔗 Perplexity,
- 🔗 GitHub Copilot,
- ou autre outil IA de votre choix.
N’hésitez pas à demander à votre agent conversationnel de reformuler sa réponse afin qu’elle soit plus simple, ou plus élégante, au moindre doute.
Retour aux fondamentaux #
Néanmoins, je me permets deux petits conseils :
De la maquette au HTML #
🔗 Aujourd’hui, OpenClassrooms fournissent un squelette de code HTML dans l’énoncé de Booki. Ce n’était pas le cas lorsque j’avais réalisé mon projet.
Outre ce point de détail, l’idée reste la même : prendre la maquette, et l’annoter pour pouvoir la transcrire en HTML.
L’annotation de vos maquettes avec des balises HTML permet de clarifier la structure et l’organisation de votre site web. Cela facilite la compréhension de la conception de votre site.
En annotant vos maquettes avec des balises HTML, vous créez une référence claire pour le codage ultérieur. Cela facilite la tâche des développeurs qui travaillent sur l’intégration, car ils comprennent immédiatement comment la conception doit être traduite en code.
La sémantique (SEO) #
Voici l’ensemble des éléments de sémantique HTML que j’ai choisi d’utiliser pour ce projet (chaque élément de la liste est cliquable et vous renverra directement vers une page de documentation) :
🔗 Google SERP Simulator
- 🔗
<header>
- 🔗
<nav>
- 🔗
<main>
- 🔗
<section>
- 🔗
<article>
- 🔗
<button>
- 🔗
<aside>
- 🔗
<footer>
- 🔗 hN (
<h1>
,<h2>
,<h3>
,<h4>
,<h5>
,<h6>
) - 🔗 Attribut
aria-label
pour le bouton de recherche , afin que l’accessibilité sur mobile reste correcte
<ul>
et <li>
peut également s’avérer sémantique !🔗 Discussion sur Stack Overflow à ce sujet
<section>
et <article>
. Celles-ci doivent
impérativement contenir au moins une balise <hN>
afin de totalement respecter les standards W3C.Le Validateur W3C (HTML) #
Le validateur W3C est un outil essentiel, car il vous permettra de vérifier si votre code HTML et CSS respectent les normes établies par le World Wide Web Consortium (W3C).
Cela vous aidera à améliorer la qualité de votre code, à améliorer la compatibilité entre différents navigateurs et rendre votre site web plus accessible aux personnes handicapées.
De plus, le respect des normes du W3C peut contribuer positivement au référencement d’un site web (SEO).
Avant de se lancer… (CSS) #
Fondamentaux #
Sélecteurs #
L’importance des sélecteurs CSS réside dans leur capacité à apporter flexibilité et précision lorsqu’il s’agit de styliser les pages web.
En utilisant des sélecteurs bien choisis, il est possible de définir des styles pour des éléments individuels, des classes d’éléments ou des groupes d’éléments, ce qui permet de personnaliser l’apparence d’une page de manière signifiante.
Par exemple :
id
(ou data
) pour la réalisation de tests automatisés.Validateur W3C (HTML/CSS) #
⬆ Nous avons déjà présenté le validateur W3C un peu plus tôt dans cet article.
Cependant, comme la page du validateur permettant d’activer ou non l’option « CSS » n’est pas évidente à trouver du premier coup…
Choix personnels #
Rappels des contraintes (arbitraires) de l’exercice #
Ce projet imposait la réalisation d’un projet totalement vanilla.
C’est-à-dire qu’il ne fallait rendre que deux fichiers : le fichier index.html
et le fichier style.css
.
Concernant le HTML #
Le code de ce projet est assez classique, et une bonne compréhension du HTML est suffisante pour en lire le code.
La seule particularité à noter est que j’ai ici fait un choix plutôt trivial quant à l’optimisation des images : afficher les images avec une
meilleure qualité selon la largeur du viewport… mais à l’inverse de ce qui aurait dû être fait : moins le viewport est large, plus la résolution des
images affichées est grande.
Je souhaitais que les images de la page d’accueil soient correctement affichées sur ordinateur lorsque l’utilisateur zoome.
Mais cela signifie aussi que les versions mobile/tablette doivent charger des images plus lourdes, car de meilleure qualité. On a donc un impact très négatif à cause de ce choix : au sacrifice de conserver un bon affichage de la page d’accueil lorsque celle-ci est zoomée sur ordinateur, on n’est pas très “Green tech” envers les mobiles et tablettes… !
🔗 Comprendre le Viewport dans le Web mobile
Une catastrophe en termes de Page speed ? #
Pour rappel : c’est l’impossibilité d’utiliser du JavaScript qui m’a fait trancher pour ce choix (contrainte arbitraire du projet…).
Malgré ce choix, les Page speeds restent très bons à l’heure où j’écris ces lignes.
Regarder ce que donnent les benchmarks des Pages speed plutôt que de partir sur des a priori #
Cela est notamment lié au design de la version mobile où seulement une image est chargée sur téléphone au-dessus de la ligne de flottaison.
En l’occurrence, cela n’a pas changé grand chose aux indicateurs.
loading="lazy"
entre temps (c’est au moins ça de pris)…Aucune de ces images ne sont dans le CSS sous forme de background image : elles sont bien toutes présentes dans des balises HTML.
Par exemple :
<a href="#">
<div class="lodging-card-wrapper has-tweakers">
<article class="lodging-card">
<picture class="thumbnail">
<source srcset="./images/hebergements/2_large/marcus-loke-WQJvWU_HZFo-unsplash.jpg" media="(max-width: 768px)" />
<source srcset="./images/hebergements/3_medium/marcus-loke-WQJvWU_HZFo-unsplash.jpg" media="(max-width: 1281px)" />
<img src="./images/hebergements/4_small/marcus-loke-WQJvWU_HZFo-unsplash.jpg" alt="Aperçu de l'Auberge La Canebière" />
</picture>
<div class="lodging-card-description">
<h3 class="is-title">Auberge La Canebière</h3>
<p class="price-p">Nuit à partir de 25<span class="is-fw-semibold">€</span></p>
<div class="rating-container">
<i class="fas fa-star is-checked" aria-hidden="true"></i>
<i class="fas fa-star is-checked" aria-hidden="true"></i>
<i class="fas fa-star is-checked" aria-hidden="true"></i>
<i class="fas fa-star is-checked" aria-hidden="true"></i>
<i class="fas fa-star is-unchecked" aria-hidden="true"></i>
</div>
</div>
</article>
</div>
</a>
Tout en honorant un Page speed tout à fait décent.
Sans JavaScript ni intelligence d’optimisation particulière.
Concernant le CSS #
Bien qu’HTML et CSS ne soient pas considérés comme des langages de programmation, et que je ne consacrerai pas mon article de blog à répondre à ce débat : le CSS est à mon sens un langage tout à fait intéressant et sur lequel on retrouve de la technicité et de l’intelligence dans son écriture.
Notions de Monkey patching et de modularisation #
Comme on en a plutôt l’habitude en programmation : le code CSS est lu de haut en bas.
🔗 Monkey patching
Simple rappel concernant la notion de surchage en CSS #
Commençons par quelque chose que (presque) tout le monde sait.
Cela fait partie des premières choses que l’on apprend concernant le CSS : c’est le dernier choix que vous faites en CSS qui est pris en compte.
Commençons par un exemple très simple :
html p {
color: red;
}
/* ... Monkey patch */
html p {
color: blue;
}
Le texte des paragraphes de ma page HTML sera bleu.
On a ici « Surchargé » la propriété color
du sélecteur html p
pour la faire passer de la valeur red
à la valeur blue
.
red
, puis un
second qui applique finalement la propriété blue
, on aurait donc modifié le comportement global de notre affichage sans modifier le premier
fichier.À présent que ce rappel a été fait : que peut-on en tirer de réellement intéressant ?
Quelle intelligence peut-on y appliquer ?
Les variables en CSS #
Il est possible depuis CSS 3 d’utiliser des variables dans ses feuilles de style.
Imaginons que l’on parte sur le nuancier suivant :
J’aurais donc seulement cinq couleurs à utiliser sur l’intégralité du design d’un produit :
- A : #005270
- B : #49C5F2
- C : #00B0F0
- D : #225B70
- E : #008ABD
J’ai à présent deux possibilités :
- Écrire partout dans mon code, en dur, #005270 dès lors que j’ai besoin de la couleur A (pas bien ! Pas bien du tout du tout !)
- Créer une variable
--primary-color
et lui donner la valeur #005270, puis écrirevar(--primary-color)
.
N’oubliez pas la notion de portée lexicale ! #
🔗 CSS variables: Scoping
Cela permet d’appliquer une intelligence encore plus fine à son utilisation des variables.
Néanmoins, dans le cas d’un nuancier à appliquer sur l’intégralité d’un produit, c’est bien plus un handicap qu’une force. C’est pour cette raison
que l’on déclarera ces variables dans le scope global, dans le pseudo-élément :root
.
Le pseudo-élément :root
en CSS
#
Le pseudo-élément :root
va nous permettre de déclarer des variables globales.
Ces variables sont utilisables dans tous les fichiers CSS d’un projet.
style.css
.Nos variables seront donc utilisables dans l’intégralité de ce fichier.
Gardez tout de même à l’esprit que dans le cas où vous ajouteriez de nouveaux fichiers CSS, ces variables y seraient également accessibles.
Je vais donc pouvoir utiliser ce pseudo-élément, comme un module de configuration globale :
:root {
/* Configuration.globalLayout => font */
--booki-font: 'Raleway';
/* Configuration.chart => Static Colors */
--booki-chart-primary: #0065fc;
--booki-chart-bg-color: #f2f2f2;
--booki-chart-sections-bg-color: white;
--booki-chart-filter-border-color: #d9d9d9;
/* Configuration.chart => FX Colors */
--booki-chart-filter-btn-hover: #deebff;
--booki-inactive-menu-elm-indicator-color: transparent;
--booki-active-menu-elm-indicator-color: var(--booki-chart-primary);
--booki-chart-blue-btn-hover: var(--booki-chart-primary);
/* ... */
}
À présent, si j’écris plus bas dans mon code CSS :
html p {
color: var(--booki-chart-primary);
}
Les paragraphes de ma page auront alors la couleur : #0065FC.
Une volonté personnelle de séparer la configuration et l’implémentation #
J’ai à présent mes variables globales dans mon pseudo-élément :root
.
Je voudrais, immédiatement après décrire la configuration globale de chacun de mes éléments dans mon code CSS.
J’aurais bien aimé pouvoir séparer ces informations dans plusieurs fichiers CSS, puis jouer avec la at-rule @import
et un bundler afin de
pouvoir tout regrouper dans un seul fichier CSS au déploiement…
Les contraintes imposées sur ce projet ne me le permettaient pas.
Afin de clarifier cette volonté dans mon choix de réalisation du projet, j’ai donc décidé d’appeler cette spécificité des Tweakers dans mon code, et
ajouté une classe .has-tweakers
sur les éléments concernés.
Ainsi :
/* Constants: Top level wrapper width */
#top-level-wrapper.has-tweakers {
--_width: 1400px;
}
/* Constants: Header nav's deadzone, header's height and its bottom gap */
#header.has-tweakers {
min-height: 65px;
margin-bottom: 55px;
}
/* Mutables: Header navigation menu's colors (NOT on mouse-over) */
.header-nav.has-tweakers {
--_menu-active-item-hyperlink-color: inherit;
--_menu-active-item-border-top-color: var(--booki-inactive-menu-elm-indicator-color);
}
/* Mutables: Header navigation menu's colors (WHEN on mouse-over) */
.header-nav-item.has-tweakers:hover {
--_menu-active-item-hyperlink-color: var(--booki-chart-primary);
--_menu-active-item-border-top-color: var(--booki-active-menu-elm-indicator-color);
border-top-width: var(--_border-top-width);
}
/* ... */
J’ai également fait le choix d’écrire sous forme de variables certaines spécifications.
Ce qui m’a permis par exemple de calculer dynamiquement la largeur du wrapper qui englobe tout le contenu de ma page web selon la largeur spécifiée
sur la maquette (1400 pixels), et ma gestion d’état du fond perdu de ma page.
/* Constants: Top level wrapper width */
#top-level-wrapper.has-tweakers {
--_width: 1400px;
}
/* ... */
/* Webpage Wrapper */
#top-level-wrapper {
/* ... */
max-width: calc(var(--_width) + var(--booki-bleed-current-state-value));
/* ... */
}
Ici, la variable --_width
n’est accessible que dans le contexte de #top-level-wrapper
et de ses éléments enfants (principe de scope).
J’ai à présent un code CSS qui commence par :
- Définir des variables globales,
- Définir des Tweakers qui permettent de m’adapter à la maquette, sans mêler le fond et la forme de mon code,
- Créer une logique de calcul interne (la notion de gestion d’états sera expliquée plus tard).
Par la suite, mon code comportera la ligne :
/* ⛔ Do NOT edit the code BELOW this line unless you know what you are doing */
Cela signifie que je signale à mon utilisateur que les lignes ci-après du code seront plus techniques : il ne s’agit plus de Tweakers que n’importe qui pourrait venir modifier sans provoquer des comportements à la fois inattendus et difficilement compréhensibles.
J’ai donc un code qui respecte une certaine notion de séparation de configuration et d’implémentation.
Par la suite, le code deviendra assez classique pour un utilisateur habitué du CSS.
Gestion d’états #
Et peut-on commencer à se rapprocher d’une logique de gestion d’états ?
Cas d’application dans Booki #
La maquette de Booki n’était pas très précise en tout point concernant l’œil de designer qu’il fallait lui apporter.
Il était question d’une largeur maximale de 1400 pixels. Mais : aucun aperçu concret de ce que donne le site sur un écran de 1920 pixels de
large. Hum…
Ce qui était attendu était de tout simplement laisser les côtés de la page transparents.
Finalement, il aurait suffi de bêtement centrer la page et laisser un fond blanc, et l’illusion aurait été suffisante…
🔗 There Will Be Bleed (and other design terms you should know)
C’est donc pour cette raison que j’ai décidé d’avoir une distinction explicite entre mon intégration des marges et du fond perdu de la page web !
À présent, si j’applique un arrière-plan qui n’est pas blanc, je vois de façon évidente que cette spécificité a bien été comprise et appliquée.
Implémentation d’une logique de largeur dynamique et de fond perdu #
Dans mon pseudo-élément :root
, je définis ma variable globale --booki-bleed-current-state-value
, et je lui donne comme valeur initiale :
var(--booki-bleed-desktop)
.
var(--booki-bleed-desktop)
vient de devenir la valeur de fallback de --booki-bleed-current-state-value
.
var(--booki-bleed-desktop)
qui a été choisi.À présent, je vais aller modifier cette variable dans mes breakpoints.
/*** D. Breakpoints */
/* ✨ [§ D.1) Bleed Manager] */
@media (max-width: 992px) {
:root {
--booki-bleed-current-state-value: var(--booki-bleed-tablet);
}
}
@media (max-width: 768px) {
:root {
--booki-bleed-current-state-value: var(--booki-bleed-mobile);
}
#content > .lodgings-section,
#content > .activities,
#top-level-wrapper > #header,
#top-level-wrapper > #footer {
padding: 0;
}
}
Et zouh ! 🎉
.has-tweakers
et le retour de bâton des spécificités de sélecteurs en CSS
#
Imaginons que j’écrive :
.filter-button.has-tweakers {
/* ... */
padding: 0.9rem 1.2rem 0.9rem 0.9rem;
/* ... */
}
Puis que je décide de monkey patch la valeur de cette propriété padding
plus bas dans mon code…
@media (min-width: 366px) and (max-width: 495px) {
.filter-button {
padding: 0.5rem 0.8rem 0.5rem 0.5rem;
}
}
Et bien : ça ne fonctionne pas !padding
reste à une valeur de .9rem 1.2rem .9rem .9rem
.
🔗 Calculer la spécificité de ses sélecteurs CSS
.filter-button.has-tweakers
sont prioritaires sur celles que l’on écrit dans
.filter-button
!Il s’agit d’une particularité dans la logique de Monkey Patch de CSS dont je n’avais pas parlé jusqu’à présent.
Aïe…
C’est très embêtant.
Mais alors que faire ?
Également écrire .filter-button.has-tweakers
dans mes media queries ?
Je trouve ce choix très ennuyeux, car j’aimerais que lorsque je navigue de .has-tweakers
en .has-tweakers
dans mon fichier CSS à l’aide du
raccourci clavier CTRL+F
, je ne puisse pas brutalement changer de contexte de configuration sans m’en rendre compte.
J’ai donc à la place fait le choix de créer une nouvelle classe, .enable-tweakers-bypass
.
Ainsi, je peux à présent patcher en contournant mon tweaker initial, de façon explicite dans mon code :
@media (min-width: 366px) and (max-width: 495px) {
.filter-button.enable-tweakers-bypass {
padding: 0.5rem 0.8rem 0.5rem 0.5rem;
}
}
Cependant, cela induit de devoir polluer mon code HTML avec une classe supplémentaire.
Bravo ! 🎉
Vous avez terminé la lecture de cet article !
Si ce n’est pas déjà fait, vous pouvez voir le résultat en lançant la démo de ce projet.
Merci de m'avoir lu.
Annexes #
Liens externes #
Workflow
Commencer HTML et CSS
- 🔗 🇫🇷 Apprendre l’HTML (Grafikart)
- 🔗 🇫🇷 Apprendre le CSS (Grafikart)
- 🔗 🇫🇷 Créez votre site web avec HTML5 et CSS3 (OpenClassrooms)
- 🔗 🇺🇸 S’entraîner sur les sélecteurs CSS : CSS Diner
- 🔗 🇺🇸 Calculer la spécificité de ses sélecteurs CSS
- 🔗 🇫🇷 Le modèle de boîte : CSS Box Model
- 🔗 :globewith_meridians: Commencer à utiliser Flexbox : _Flexbox froggy
- 🔗 :globewith_meridians: Commencer à utiliser CSS Grids : _Grid garden
- 🔗 🇺🇸 Se perfectionner en CSS : CSS Tricks
Astuces de normalisation CSS
Notions de design
Optimisation du chargement des polices
Sémantique (HTML)
Captures d’écran #
Si ce n’est pas déjà fait, vous pouvez voir le résultat en lançant la démo de ce projet.