Cet exercice consiste à rendre adaptable (au sens de responsive web design) une interface web fournie.
Consignes de l’exercice
Créez un dossier racine à l’emplacement de votre choix.
Téléchargez les fichiers de travail en cliquant ci-dessous et placez les dans votre dossier racine. Il existe deux versions de l’interface, une version construite avec un grille (Grid) et une deuxième qui utilise uniquement du positionnement Flexbox. Vous pouvez choisir celle que vous préférez pour travailler. Les fichiers SCSS sont fournis, il est recommandé de les refaire à partir des fichiers CSS.
Pour télécharger un fichier, faites un clic droit sur le fichier désiré et choisissez l’option Télécharger.
Pour télécharger plusieurs fichiers, sélectionnez les fichiers désirés puis cliquez sur Télécharger les sélectionnés. Les fichiers seront téléchargés sous la forme d’une archive .zip. Veillez à bien extraire le contenu de l’archive avant de commencer à travailler.
L’interface téléchargée à une largeur fixe exprimée en pixels, elle ne s’adapte donc pas du tout à la taille de la fenêtre du navigateur. Modifiez l’interface afin de la rendre fluide : largeur exprimée en pourcentage mais bornée (ex : 1200px maximum).
Étape 1 : On modifie les dimensions du conteneur pour le rendre flexible.
.page { width: 100%; max-width: 1400px; margin: auto; display: grid; grid-template-columns: 160px auto 160px; grid-template-rows: auto auto 180px auto auto; grid-template-areas: "header header header" "menu menu menu" "hero hero hero" "aside1 content aside2" "footer footer footer"; border-radius: 4px; overflow: hidden; }
Étape 2 : Modification de l’image en bandeau
.home div.hero { grid-area: hero; width: 100%; height: 180px; background-image: url("img.jpg"); position: relative; background-size: cover; background-position: center center; }
Étape 1 : On modifie les dimensions du conteneur pour le rendre flexible.
.page { max-width: 1400px; margin: auto; display: flex; flex-wrap: wrap; border-radius: 4px; overflow: hidden; }
Étape 2 : Modification de l’image en bandeau
.home div.hero { grid-area: hero; width: 100%; height: 180px; background-image: url("img.jpg"); position: relative; background-size: cover; background-position: center center; }
Étape 3 : On redéfinit la largeur du contenu principal. Les 300px correspondent à la largeur cumulée des deux éléments aside.
section.main_content { background-color: #ffffff; width: calc(100% - 300px); min-height: 200px; order: 3; box-sizing: border-box; padding: .5em; }
L’objectif va être de rendre l’interface adaptable (responsive). Préparez les media queries permettant de gérer trois largeurs d’écran :
- Pour un viewport d’une largeur supérieure à 960px (interface par défaut) ;
- Pour un viewport d’une largeur comprise entre 576px et 960px ;
- Pour un viewport d’une largeur inférieure à 576px.
Nous n’allons pas prévoir de media queries pour la taille par défaut, mais uniquement pour les deux autres largeurs d’écran. Il suffira alors d’apporter les modifications entre l’interface par défaut et la largeur d’écran définie par les media queries.
/* Paramètres pour les écrans avec une largeur inférieure à 576px */ @media screen and (max-width: 575px) { } /* Paramètres pour les écrans d'une largeur comprise entre à 577px et 960px */ @media screen and (min-width: 576px) and (max-width: 960px) { }
Ajustez les paramètres de l’interface afin qu’elle corresponde à l’image ci-dessous pour les écrans ayant une largeur comprise entre 576px et 960px.
@media screen and (min-width: 576px) and (max-width: 960px) { /* Modification de la grille pour repositionner les éléments */ .page { grid-template-columns: 1fr 1fr; grid-template-rows: auto auto 180px auto auto auto; grid-template-areas: "header header" "menu menu" "hero hero" "content content" "aside1 aside2" "footer footer"; } /* Modification du menu */ nav.main-nav ul { justify-content: flex-start; } nav.main-nav a { border-radius: 0px; } nav.main-nav li:first-of-type { border-radius: 5px 0 0 5px; } nav.main-nav li:last-of-type { border-radius: 0 5px 5px 0; } /* Modification des bordures pour les deux éléments aside */ aside.main_aside_left, aside.main_aside_right { border: 5px solid #7e52a0; } aside.main_aside_left { border-width: 5px 3px 0 0; } aside.main_aside_right { border-width: 5px 0 0 3px; } }
@media screen and (min-width: 576px) and (max-width: 960px) { nav.main-nav ul { justify-content: flex-start; } nav.main-nav a { border-radius: 0px; } nav.main-nav li:first-of-type { border-radius: 5px 0 0 5px; overflow: hidden; } nav.main-nav li:last-of-type { border-radius: 0 5px 5px 0; overflow: hidden; } section.main_content{ order: 1; width: 100%; } aside.main_aside_left, aside.main_aside_right { order: 2; width: 50%; border: 5px solid #7e52a0; } aside.main_aside_left{ border-width: 5px 3px 0 0 ; } aside.main_aside_right{ border-width: 5px 0 0 3px ; } }
Ajustez les paramètres de l’interface afin qu’elle corresponde à l’image ci-dessous pour les écrans ayant une largeur inférieure à 576px.
@media screen and (max-width: 575px) { body { margin: 0; } .page { border-radius: 0px; grid-template-columns: 1fr; grid-template-rows: repeat(6, auto); grid-template-areas: "header " "menu" "content" "aside1" "aside2" "footer"; } nav.main-nav ul { flex-direction: column; } nav.main-nav a { border-radius: 0px; } nav.main-nav li:first-of-type a { border-radius: 5px 5px 0 0; } nav.main-nav li:last-of-type a { border-radius: 0 0 5px 5px; } .home div.hero { background: none; display: none; } aside.main_aside_left, aside.main_aside_right { border: 5px solid #7e52a0; border-width: 5px 0 0 0; } footer.main_footer ul { margin: 0; padding: .5em 1em; border-top: 1px solid #d295bf; width: 100%; } }
@media screen and (max-width: 575px) { body { margin: 0; } nav.main-nav ul { flex-direction: column; } nav.main-nav a { border-radius: 0px; } nav.main-nav li:first-of-type { border-radius: 5px 5px 0 0; overflow: hidden; } nav.main-nav li:last-of-type { border-radius: 0 0 5px 5px; overflow: hidden; } .home div.hero { background: none; display: none; } section.main_content { order: 1; width: 100%; } aside.main_aside_left, aside.main_aside_right { border: 5px solid #7e52a0; border-width: 5px 0 0 0; flex-basis: 100%; } footer.main_footer ul { margin: 0; padding: .5em 1em; border-top: 1px solid #d295bf; width: 100%; } }
Modifiez le code afin d’ajouter un bouton hamburger qui permettra d’afficher le menu pour les écrans ayant une largeur inférieure à 576px. Il existe de nombreuses solutions pour gérer l’affichage du menu. Souhaitez-vous utiliser du Javascript ou uniquement du CSS ? Souhaitez-vous ajouter un effet d’animation lors de l’affichage du menu ou non ? Connaissez-vous la hauteur du menu ou non ? Les solutions que je propose ici seront le plus simple possible, exclusivement en CSS et avec effet d’animation. Le bouton hamburger sera créé à partir du label d’une case à cocher qui déterminera si le menu est visible ou pas.
Cette première solution est la plus simple à mettre en œuvre.
Étape 1 : Mise en place du bouton
Le bouton hamburger va être créé à partir du label
associé à la checkbox. Pour associer un label
à une checkbox, il est nécessaire d’ajouter un id
à l’input et un for
correspondant au label. Ainsi, il sera possible de cocher la case en cliquant sur le label en plus de la case. Le span
ajouté à l’intérieur du label sera utilisé pour créer le trait central du bouton.
<nav class="main-nav"> <input type="checkbox" class="btn-hamburger" id="btn-hamburger"> <label for="btn-hamburger" class="btn-hamburger-label" ><span></span></label> <div> <ul> <li><a href="#" class="active">Accueil</a></li> <li><a href="#">Page 1</a></li> <li><a href="#">Page 2</a></li> <li><a href="#">Page 3</a></li> </ul> </div> </nav>
Étape 2 : Mise en forme du bouton
Nous commençons par masquer la case à cocher d’origine. Puis nous allons créer le bouton hamburger. Celui-ci se compose de trois traits. Les trois traits sont créés à partir du span
présent dans le label
et des deux pseudo-éléments ::before
et ::after
.
/* Masquage de la case à cocher */ input.btn-hamburger { display: none; } /* Création des trois traits du bouton de menu */ .btn-hamburger-label { width: 30px; height: 30px; margin: 10px auto 10px; padding-top: 2px; display: flex; justify-content: space-between; flex-direction: column; cursor: pointer; } .btn-hamburger-label span, .btn-hamburger-label::before, .btn-hamburger-label::after { content: ''; display: block; width: 100%; height: 7px; margin: 2px 0; background-color: #29274c; border-radius: 10px; }
Étape 3 : Animation du menu
L’état affiché ou masqué du menu est déterminé par la pseudo-classe :checked
de l’élément input. Dans notre exemple, allons donc affiché l’élément div contenant notre menu en manipulant sa hauteur. Le problème est que CSS ne permet pas d’effectuer une transition entre height: 0
et height: auto
. Nous allons donc utiliser max-height
en lui attribuant une valeur qui doit être supérieure à la hauteur maximale du menu ouvert.
input.btn-hamburger { display: none; } input.btn-hamburger ~ div { transition: all 1s; overflow: hidden; max-height: 0px; } input.btn-hamburger:checked ~ div { max-height: 200px; }
Inconvénients de cette solution :
- Vous devez définir une hauteur maximale supérieure à la hauteur du menu dont vous ne connaissez pas forcément la hauteur.
- Si hauteur maximale est trop élevée, l’effet d’animation accuse du retard, car il s’applique sur toute la hauteur définie par
max-height
.
Cette seconde solution permet de contourner en partie les inconvénients de la solution précédente.
Étape 1 : Mise en place du bouton
Idem que pour la solution 1.
Étape 2 : Mise en forme du bouton
Idem que pour la solution 1.
Étape 3 : Animation du menu
S’il est difficile d’évaluer la hauteur du menu lorsque l’on ne connait pas son contenu, il est beaucoup plus simple d’évaluer celle d’une ligne du menu.
input.btn-hamburger { display: none; } input.btn-hamburger ~ div li { transition: all 1s; overflow: hidden; max-height: 0px; } input.btn-hamburger:checked ~ div li { max-height: 2rem; }
Inconvénients de cette solution :
- Le principal problème de cette solution est d’ordre esthétique.
Prévoyez une version pour l’impression centrée sur le contenu et dépourvue des éléments suivants : menu, image hero, asides, footer.
@media print { .page { grid-template-columns: 1fr ; grid-template-rows: auto auto; grid-template-areas: "header" "content"; } }
Ajoutez des effets de transition lors du redimensionnement de la fenêtre du navigateur. Notez que les effets de transition ne s’appliquent pas lors d’un changement de grille de template. Ils seront donc beaucoup moins nombreux dans la version grid que dans la version flexbox.
Nous utilisons le sélecteur universel pour définir une transition par défaut à l’ensemble des éléments.
* { transition: all 1s; }
Personnalisez les couleurs de l’interface pour les adapter à votre goût. Idéalement, il s’agirait de mettre toutes les couleurs en variables (CSS ou SCSS).
Assurez-vous d’ajouter les préfixes vendeurs nécessaires. Il s’agit ici d’utiliser les outils nécessaires permettant d’éviter d’avoir à gérer manuellement les préfixes vendeurs (autoprefixer, mixins compass ou bourbon, etc.).
Bonjour,
Tout d’abord, merci beaucoup pour ce tutoriel très utile !
Est-ce possible d’avoir le corrigé ?
Merci par avance.
Bonjour Karim,
Désolé pour ma réponse tardive… Je suis sur le coup, je l’ai commencé et vous devriez l’avoir intégralement d’ici quelques jours.