Interface adaptable (responsive) en CSS CSS23

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.

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).

Afficher la solution CSS (version Grid)

Solution CSS (version Grid) :

É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;
}
Afficher la solution CSS (version Flexbox)

Solution CSS (version Flexbox) :

É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 :

  1. Pour un viewport d’une largeur supérieure à 960px (interface par défaut) ;
  2. Pour un viewport d’une largeur comprise entre 576px et 960px ;
  3. Pour un viewport d’une largeur inférieure à 576px.
Afficher la solution CSS

Solution CSS :

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.

Aperçu de l'interface entre 576px et 960px
Afficher la solution CSS (version Grid)

Solution CSS (version Grid) :

@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;
  }
}
Afficher la solution CSS (version Flexbox)

Solution CSS (version Flexbox) :

@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.

Interface inférieure à 576px
Afficher la solution CSS (version Grid)

Solution CSS (version Grid) :

@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%;
  }
}
Afficher la solution CSS (version Flexbox)

Solution CSS (version Flexbox) :

@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.

Ajout du menu hamburger
Afficher la solution 1

Solution 1

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;
}
Démonstration de la solution 1

Inconvénients de cette solution :

  1. Vous devez définir une hauteur maximale supérieure à la hauteur du menu dont vous ne connaissez pas forcément la hauteur.
  2. 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.

Afficher la solution 2

Solution 2 :

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;
}
Démonstration de la solution 2

Inconvénients de cette solution :

  1. 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.

Afficher la solution CSS (version Grid)

Solution CSS (version Grid) :

@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.

Afficher la solution

Solution :

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.).

Sauf mention contraire*, l'article Interface adaptable (responsive) en CSS [CSS23] et son contenu par Julien Crego sont mis à disposition selon les termes de la licence Creative Commons

Licence Creative Commons

Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International

Cette licence vous permet de remixer, arranger, et adapter cette œuvre à des fins non commerciales tant que vous créditez la source en citant le nom des auteurs et que les nouvelles œuvres sont diffusées selon les mêmes conditions.

* Cette notice est intégrée automatiquement à la fin de chaque article de ce site.

2 réactions sur “ Interface adaptable (responsive) en CSS [CSS23] ”

  1. Karim Réponse

    Bonjour,

    Tout d’abord, merci beaucoup pour ce tutoriel très utile !
    Est-ce possible d’avoir le corrigé ?
    Merci par avance.

    • Julien Crego Auteur ArticleRéponse

      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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.