Nouveaux styles de menu mobile pour Divi

15 Juin 2018

Salut à tout-te-s,

Voici un second tutoriel sur la personnalisation du menu mobile Divi.

J’avais déjà expliqué comment améliorer l’apparence du menu déroulant en supprimant ses marges et en modifiant l’apparence du texte.

Aujourd’hui nous irons plus loin en redéfinissant complètement la façon d’afficher le menu mobile lorsqu’on appuie sur l’icône associée (le fameux hamburger). Nous verrons ainsi comment modifier indépendamment hauteur, largeur et animation, ce qui vous permettra de créer votre propre style, par exemple :

  • slide in ou expand sous l’entête, sur le côté ou en pleine largeur,
  • slide in sur le côté en pleine hauteur,
  • plein écran avec animation au choix.

Prérequis : Configuration du menu dans Divi

Ce tutoriel ne s’applique qu’au style de menu par défaut de Divi (à définir dans la personnalisation du thème), à savoir le logo à gauche et le menu à droite.

J’essaierai d’adapter le code CSS suivant pour les menus centré et centré inline dans un prochain épisode.

Vous pouvez maintenant continuer à lire les explications, ou sauter directement aux exemples de menu mobile à copier/coller dans le CSS personnalisé de Divi ou dans la feuille de style de votre thème enfant.

Introduction au menu mobile Divi

Même si un simple copier/coller vous permettra de modifier votre menu mobile sans comprendre, voici une courte introduction à son code source pour les curieux et les développeurs en herbe.

Le menu mobile Divi se compose grossièrement de deux éléments :

  • l’entête, défini par les divs .logo_container et #et-top-navigation, inclus dans le div #main-header ;
  • le menu déroulant, défini par la liste ul#mobile_menu, encapsulée dans le div .mobile_nav, lui même encapsulé dans #et-top-navigation.

Cependant, le squelette du code source est un peu plus complexe car il y a pleins de cas à gérer en fonction des réglages du thème et de la largeur de l’écran (avec le menu desktop).

Mais ce qui nous intéresse aujourd’hui peut se résumer au squelette HTML suivant :

<header id="main-header">
	<div class="container clearfix et_menu_container">
		<div class="logo_container"></div>
		<div id="et-top-navigation">
			<div id="et_mobile_nav_menu">
				<div class="mobile_nav opened">
					<span class="mobile_menu_bar mobile_menu_bar_toggle"></span>
					<ul id="mobile_menu" class="et_mobile_menu"></ul>
				</div>
			</div>
		</div> <!-- #et-top-navigation -->
	</div> <!-- .container -->
</header>

Afin de modifier largeur, hauteur et animation du menu déroulant, nous toucherons principalement à la liste ul#mobile_menu, mais il faudra quand-même modifier quelques éléments supplémentaires pour que tout fonctionne correctement.

Icône de fermeture

Le minimum syndical (quand-même, ET…), on remplace le hamburger par une croix lorsque le menu est ouvert :

@media only screen and (max-width: 980px) {

	.mobile_nav.opened .mobile_menu_bar:before {
		content: "d";
	}

}

Suppression des marges

Les marges droite et gauche du menu mobile Divi doivent être supprimées. D’une part pour préserver vos yeux, et d’autre part pour pouvoir afficher proprement le menu en plein écran ou pleine largeur, et obtenir des transitions propres.

On doit donc élargir le conteneur principal et adapter la position du logo et de l’icône hamburger :

@media only screen and (max-width: 980px) {

	#main-header .container.clearfix.et_menu_container {
		width: 100%;
	}
	.logo_container {
		padding-left: 30px;
	}
	#et-top-navigation {
		padding-right: 30px;
	}

}

Positionnement du menu

Le menu peut être affiché sous l’entête, ou démarrer en haut de l’écran (pleine hauteur ou plein écran). Dans le second cas, on supprime le bord supérieur de couleur qui sinon se retrouverait collé en haut de l’écran, et on ajoute un padding vertical pour laisser la place au logo et à l’icône de fermeture du menu. Il faut également positionner le z-index du logo et du bouton de fermeture au-dessus du menu déroulant pour y avoir encore accès.

Un menu slide-in horizontal peut venir de la droite ou de la gauche, donc on fixera sa position d’un côté ou de l’autre, et on positionnera le côté opposé en automatique puisque la largeur du menu peut être variable.

@media only screen and (max-width: 980px) {

	#mobile_menu {
		display: block !important;

		/* Slide-in droite */
		right: 0;
		left: auto;
		/* Slide-in gauche */
		right: 0;
		left: auto;
		/* Expand */
		right: 0;
		left: 0;
		
		/* Sous l'entête */
		top: 80px;
		/* Plein écran ou pleine hauteur */
		top: 0;
		padding-top: 80px;
		border-top: none;
	}

	/* Pleine hauteur */
	.mobile_menu_bar, #logo {
		z-index: 10000;
	}

}

Largeur du menu

La largeur du menu est de 100% par défaut, mais on peut simplement la modifier avec :

@media only screen and (max-width: 980px) {

	#mobile_menu {
		width: 400px;
	}

}

A noter qu’on pourra si besoin utiliser un media query pour limiter la largeur du menu au-delà d’une certaine taille d’écran, mais la repositionner à 100% en-deça pour éviter un affichage trop serré :

@media only screen and (max-width: 480px) {

	#mobile_menu {
		width: 100%;
	}

}

Hauteur du menu

La hauteur du menu s’adapte par défaut à la longueur de la liste contenant les éléments du menu, ce qui nous va très bien.

Mais on pourra imposer au menu d’occuper au moins la hauteur de l’écran (menu plein écran ou slide in pleine hauteur) :

@media only screen and (max-width: 980px) {

	#mobile_menu {
		min-height: 100vh;
	}

}

ou seulement la hauteur disponible sous l’entête :

@media only screen and (max-width: 980px) {

	#mobile_menu {
		min-height: calc( 100vh - 80px );
	}

}

Animation du menu

Le point le plus délicat dans l’affichage du menu réside dans l’animation CSS qui permet de faire apparaître la liste composant le menu.

Il faut savoir par exemple que si positionner l’opacité à 0 permet bien de masquer le menu déroulant, cela ne supprime pas la liste physiquement, et tous les liens du menu sont encore cliquables ! Même en modifiant la propriété z-index, je n’ai pas réussi à l’éviter. Si vous avez une astuce pour un fade-in simple, je suis preneur…

Ou encore, sur un système iOS, la gestion du « overflow: hidden » sur les éléments body et html est un peu étrange, et un ascenseur horizontal apparaît lorsqu’on veut « pousser » le menu hors de l’écran dans le cas d’un menu slide in.

Donc pour contourner ces deux problèmes, la seule solution simple et globale que j’ai pu trouver (sur le net, j’avoue, pas en moi) est d’utiliser une rotation de la liste dans l’espace, pour la positionner perpendiculairement au plan de l’écran ! Ainsi, elle est physiquement introuvable et elle n’a pas besoin d’être sortie de l’écran.

Par exemple, pour l’animation que j’appelle expand, j’effectue une rotation par rapport à l’axe vertical passant par le centre du menu, ce qui donne l’impression qu’il s’étend du centre vers les bords.

Pour le slide in, la rotation se fait par rapport à l’axe vertical passant par un bord (droit ou gauche), ce qui simule un déplacement latéral.

Pour dérouler à partir du haut, on utiliserait l’axe horizontal passant par le bord supérieur, etc…

Je ne vais pas détailler ici chaque animation, vous pourrez les voir dans les exemples ci-dessous. Vous remarquerez au passage que j’ai réduit le temps de transition à 200ms car je trouve que par défaut l’apparition du menu est vraiment trop lente.

Couleurs du menu

Par défaut, le menu mobile déroulant utilise les mêmes couleurs que l’entête, donc celles définies pour la barre primaire dans la personnalisation du thème.

On peut les personnaliser avec :

@media only screen and (max-width: 980px) {

	#mobile_menu {
		background-color: #fff !important;
	}
	#mobile_menu li a {
		color: #333;
	}

}

Exemple 1 : Menu mobile « expand » pleine largeur qui s’ouvre sous l’entête

Code CSS à ajouter à votre feuille de style (par exemple le fichier style.css de votre thème enfant) ou dans le CSS personnalisé des options Divi.

/* Menu mobile "expand" pleine largeur qui s'ouvre sous l'entête */
@media only screen and (max-width: 980px) {

	.mobile_nav.opened .mobile_menu_bar:before {
		content: "d";
	}
	#main-header .container.clearfix.et_menu_container {
		width: 100%;
	}
	.logo_container {
		padding-left: 30px;
	}
	#et-top-navigation {
		padding-right: 30px;
	}
	#mobile_menu {
		display: block !important;
		right: 0;
		left: 0;
		top: 80px;
		min-height: calc( 100vh - 80px );
		transition: all .2s ease-in-out;
		transform-origin: center;
	}
	.mobile_nav.closed #mobile_menu {
		transform: rotateY(90deg);
		opacity: 0;
	}
	.mobile_nav.opened #mobile_menu {
		transform: rotateY(0);
		opacity: 1;
	}

}

Exemple 2 : Menu mobile « slide-in » pleine hauteur qui sort du côté droit

Code CSS à ajouter à votre feuille de style (par exemple le fichier style.css de votre thème enfant) ou dans le CSS personnalisé des options Divi.

/* Menu mobile "slide-in" pleine hauteur qui sort du côté droit */
@media only screen and (max-width: 980px) {

	.mobile_nav.opened .mobile_menu_bar:before {
		content: "d";
	}
	#main-header .container.clearfix.et_menu_container {
		width: 100%;
	}
	.logo_container {
		padding-left: 30px;
	}
	#et-top-navigation {
		padding-right: 30px;
	}
	.mobile_menu_bar, #logo {
		z-index: 10000;
	}
	#mobile_menu {
		display: block !important;
		right: 0;
		left: auto;
		top: 0;
		padding-top: 80px;
		min-height: 100vh;
		width: 400px;
		border-top: none;
		transition: all .2s ease-in-out;
		transform-origin: right;
	}
	.mobile_nav.closed #mobile_menu {
		transform: rotateY(90deg);
		opacity: 0;
	}
	.mobile_nav.opened #mobile_menu {
		transform: rotateY(0);
		opacity: 1;
	}

}

@media only screen and (max-width: 480px) {

	#mobile_menu {
		width: 100%;
	}

}

Exemple 3 : Menu mobile « slide-in » plein écran qui vient d’en bas

Code CSS à ajouter à votre feuille de style (par exemple le fichier style.css de votre thème enfant) ou dans le CSS personnalisé des options Divi.

/* Menu mobile "slide-in" plein écran qui vient d'en bas */
@media only screen and (max-width: 980px) {

	.mobile_nav.opened .mobile_menu_bar:before {
		content: "d";
	}
	#main-header .container.clearfix.et_menu_container {
		width: 100%;
	}
	.logo_container {
		padding-left: 30px;
	}
	#et-top-navigation {
		padding-right: 30px;
	}
	.mobile_menu_bar, #logo {
		z-index: 10000;
	}
	#mobile_menu {
		display: block !important;
		right: 0;
		left: 0;
		top: 0;
		padding-top: 80px;
		min-height: 100vh;
		border-top: none;
		transition: all .2s ease-in-out;
		transform-origin: bottom;
	}
	.mobile_nav.closed #mobile_menu {
		transform: rotateX(90deg);
		opacity: 0;
	}
	.mobile_nav.opened #mobile_menu {
		transform: rotateX(0);
		opacity: 1;
	}

}

Conclusion

Dans le code source de Divi, l’apparition du menu mobile se fait en java : le CSS permettant de gérer son affichage est modifié dynamiquement. Heureusement, nous avons pu directement modifier ce comportement en CSS.

Cependant, une fois de temps, si on clique trop vite, par exemple, quand le menu apparait, il peut y avoir un mouvement vertical du menu, ou un léger délai dans l’affichage. Je pense que selon la longueur de l’animation choisie et le moment où on clique, la transition CSS entre en conflit avec le code java de Divi qui s’exécute en parallèle.

Donc pour une animation parfaite dans 100% des cas, il faudrait modifier Divi pour désactiver ce code. Si quelqu’un a une idée propre et simple…

A partir de ces quelques exemples, j’espère que vous saurez innover et créer des menus mobiles toujours plus beaux et plus design !