Un sous-menu eXtra Large avec jQuery

Assez des menus déroulants qui se positionnent au-dessus des contenus et souvent peu esthétiques ? Je vous propose un petit tutoriel pour faire un sous-menu qui donnera une autre dimension à vos pages.

Beaucoup de sites utilisent une large bande qui court de gauche à droite avec souvent une liste de liens les uns à côté des autres et la technique la plus utilisée pour faire des sous-menu est un menu déroulant qui vient couler sous le lien en superposant au contenu du dessous. Personnellement, je trouve cela pas très agréable graphiquement ou dans de rares cas. Voici un article sur le sujet sur Smashing Magazine.

J’ai déjà expérimenté le menu que je vais vous présenter sur un site qui sera bientôt ajouté dans le portfolio, mais il était plus complexe grâce au concours du légendaire Fabien, qui si il passe par ici, ne me maudira pas trop en voyant cet article j’espère. En effet il existe de nombreuses façon de réaliser cet effet et la mienne n’est surement pas la plus optimisée, mais elle a le mérite de fonctionner.

Voici la démonstration du menu
Et le pack à télécharger.

Dans cet exemple il faudra cliquer sur le lien pour faire apparaître le sous menu et le fermer, mais il serait tout à fait possible de faire l’effet en hover.

Rentrons un peu dans les détails de la structure de ce menu. L’idée est de repousser tout le contenu de la page pour faire apparaître le sous-menu.
La méthode que j’ai utilisé est de créer des zones pour chaque parties de la structure, une pour le header (menu principal), une pour le sous-menu et enfin une pour le contenu.
La seule complexité étant que j’ai associé le sous-menu à la liste du menu principal, donc la zone du menu est vide… Voyez plutôt la structure HTML :


fleur

Le menu large

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

On distingue bien les 3 zones de la page.
Pour bien positionner les div du sous-menu, nous allons la placer en absolute par rapport au header et de façon à ce qu’elles se retrouvent juste sous le menu principal. Le menu principal est donc placé avec un float:right et l’autre avec un right:0. Les boutons pourront donc s’étaler sur toute la largeur de la page.

Voici d’ailleurs le CSS complet :

/*-----------------Patie générique------------------*/
body {
	margin:0;
	font-family:Tahoma, Verdana, Geneva, Arial, Helvetica, sans-serif;
}
h2 { margin-top:0; }
a {
	text-decoration:none;
	outline:none;
}
ul {
	padding:0;
	margin:0;
}
li { list-style:none; }
a.titre {
	float:left;
	width:180px;
	color:#6d8a20;
	font-size:36px;
	line-height:48px;
	font-weight:normal;
}
/*-----------------Patie menu principal------------------*/
#wrap_header {
	width:100%;
	height:50px;
	background:#91b439;
	border-top:1px solid #aad246;
	border-bottom:1px solid #6d8a27;
}
#header {
	width:950px;
	height:50px;
	margin:0 auto;
	position:relative;
}
#header ul {
	float:right;
	border-left:1px solid #6d8a27;
	border-right:1px solid #aad246;
}
#header li {
	padding:0;
	float:left;
	height:50px;
	line-height:50px;
	border-left:1px solid #aad246;
	border-right:1px solid #6d8a27;
}
#header li a {
	display:block;
	color:#fff;
	padding:0 30px;
	height:50px;
}
#header li a.down {
	padding-left:40px;
	background:url(../images/puce.gif) 20px center no-repeat;
}
#header li a:hover { background:#aad246; }
#header li a.down:hover,
#header li a.active { background:#aad246 url(../images/puce.gif) 20px center no-repeat; }

/*-----------------Patie sous-menu------------------*/
#header li div {
	position:absolute;
	top:52px;
	right:0;
}
#header li div ul {
	border:none;
	border-left:1px solid #fff;
	margin-left:0;
}
#header li div li {
	border:none;
	border-right:1px solid #fff;
}
#header li div a {
	height:20px;
	line-height:20px;
	color:#474747;
	height:49px;
	line-height:49px;
	float:left;
}
#header li div a:hover {
	background:none;
	color:#6d8a27;
}

#wrap_menu {
	width:100%;
	height:0px;
	background:#ddd;
}
/*-----------------Patie Contenu------------------*/
#wrap_body {
	width:100%;
	background:url(../images/degr.png) repeat-x;
	height:200px;
	border-top:1px solid #fff;
}
#body {
	width:950px;
	margin:0 auto;
	padding:30px 0;
}
#body img {
	float:right;
	margin-left:10px;
}

Rien de bien compliqué. Alors je passe au javascript que j’ai commenté au fur et à mesure (il utilise jQuery qu’il faudra appeler bien sûr) :

$(document).ready(function () {
	$("#header li div").hide(); //Cache les sous-menus

	$(".down").click( function (){ //Quand on clique sur les liens avec la class 'down'
		if ($(this).next("div").hasClass ("open")) { //Si le sous-menu du lien cliqué est ouvert
			$(this).removeClass ("active"); //On retire la class active du lien
			$(this).next("div").removeClass ("open").stop(true, true).fadeOut ( function () { //On retire la class open du sous-menu et on le fait disparaître
				$("#wrap_menu").animate ({ //Puis on ferme l'espace sous-menu
					height: 0 + "px"
				}, 500);
			});
		}
		else { //Si le sous-menu n'est pas ouvert
			if ($("#header li div").hasClass ("open")) { //Mais qu'un autre sous-menu est ouvert
				$(".active").removeClass ("active"); //On retire la class active de l'autre lien
				$(this).addClass ("active"); //Qu'on place sur celui-ci
				$(".open").fadeOut ("fast").removeClass ("open"); //On fait disparaître l'autre sous-menu et on retire sa class open
				$(this).next("div").addClass ("open").fadeIn("slow"); //Et on fait apparaître celui ciblé
			}
			else { //Si aucun sous-menu n'est ouvert
				$(this).addClass("active"); //On ajoute la class active au lien
				$(this).next("div").addClass ("open").fadeIn(2000); //Et la class open au sous-menu qu'on fait apparaître
				$("#wrap_menu").animate({ //En même temps on ouvre l'espace sous-menu
					height: 50 + "px"
				}, 500);
			}
		}
		return false; //'Désactive' les liens du menu principal avec la class down
	});
});

menu

J’espère que cet article vous aura inspiré, et si vous avez d’autres façons de faire ce menu XL, n’hésitez pas à les partager !
A bientôt !

17 réponses à “Un sous-menu eXtra Large avec jQuery”

  1. 1
    galerie dit :

    laisser un commentaire si vous voulez mettre du code dans vos messages -> j’ai dumal à comprendre !

    • 1.1
      admin dit :

      Bonjour,
      Je ne comprends pas bien ce que vous ne comprenez pas, ‘Laisser un commentaire’ et ‘Si vous voulez mettre du code dans vos messages’ sont deux phrases différentes.
      Tout simplement si vous voulez écrire du HTML, du CSS ou du javascript (comme dans mon article), vous pouvez le faire en utilisant les balises indiquées, sinon votre code sera mal interprété par le générateur de commentaires, surtout pour le HTML.

      Exemple :

      < .pre class="brush: CSS;">
              Ici votre CSS ....
      < ./pre>
      

      (Bien sûr sans les points avant pre et /pre.)
      J’espère que c’est plus clair, merci d’être passé par ce site, à bientôt. :)

  2. 2
    Mathieu dit :

    Bonjour,votre code m’a bien aidé,mais par contre il y a une erreur lorsque l’on clique sur menu 2 alors que le sous menu de menu 1 est ouvert,les 2 sous menu se superposent :/

    • 2.1
      admin dit :

      Bonjour,
      Si vous avez recopié tel quel le script, cela devrait fonctionner comme dans l’exemple.
      Sinon, je suppose qu’il ne trouve pas la class de l’élément qu’il doit fermer, alors il passe à côté :

      $(".open").fadeOut ("fast").removeClass ("open");
      

      (ligne 17 du script au dessus)
      Cette class est-elle bien appliquée à l’élément qui est ouvert ?

      Désolé, c’est difficile d’aider sans voir le script. Vous pouvez le poster ici dans une balise pre associée à la class ‘brush: javascript’

      Merci néanmoins de l’intérêt porté à ce script.
      Bonne continuation

  3. 3
    ingelf-web dit :

    tres interessant, merci

  4. 4
    Wally dit :

    Comment avoir un menu ouvert par défaut ?

    • 4.1
      admin dit :

      Salut,
      Merci pour l’intérêt porté à cet article.
      Alors pour avoir un menu par défaut ouvert, il y a 2 méthodes.
      Actuellement on masque les menu dans le script au début. Tu peux donc ajouter une petite ligne à la suite pour spécifier que tu souhaites en ouvrir un.
      $(« #header li div:eq(n) »).hide();
      ‘n’ étant le numéro de ton menu (commencer le compte à 0; 0 = 1) ou bien $(« #header li div:first »).hide(); si c’est le premier.

      Sinon tu enlèves la ligne qui cache les menu dans le script et tu les masques en CSS avec un bon vieux display:none; et tu affiches seulement celui que tu souhaites en le signalant dans le HTML.

      La première solution me semble quand même meilleur.
      J’espère que c’est clair.

      Dans le même genre de menu, j’ai fait récemment celui-ci qui est un peu plus abouti, même s’il ne s’agit que d’une maquette (2 premiers lien du menu actif seulement)
      http://test.goweb.fr/CHARTES/keolis/_integration/index.html

      Bonne continuation.

  5. 5
    Wally dit :

    Merci ca marche niquel ! Et pour marquer le premier lien supérieur Comme Actif par défaut une solution ?

    • 5.1
      admin dit :

      Tu dois ajouter la class active juste avant ou après avoir masqué les menus :
      $(‘#header .down:first’).addClass(‘active’);
      Si c’est le premier. :)

  6. 6
    Wally dit :

    Par contre il faut mettre : $(« #header li div:first »).show();

  7. 7
    Nicolas dit :

    Bonjour,
    Merci pour ce script, qui est parfait.

    Néanmoins, j’ai le même soucis qui est évoqué plus haut.
    La fonction removeclass, n’a pas l’air de fonctionner après mise en ligne quand je clique sur un autre lien de menu.
    Du coup les 2 menus se superposent.
    Par contre, si je clique une deuxième fois sur un menu, celui-ci se ferme bien…

    Merci pour votre aide.

    • 7.1
      Nicolas dit :

      Je me réponds à moi même, il y a une petite erreur dans le javascript :)
      En effet au lieu de

      if ($(« #header li div »).hasClass (« .open »)) { //Mais qu’un autre sous-menu est ouvert

      il faut enlever le point devant l’argument « open » dans la fonction hasClass

      if ($(« #header li div »).hasClass (« open »)) { //Mais qu’un autre sous-menu est ouvert

      Merci encore pour le script ! :)

      • admin dit :

        Bien vu ;) (édité)
        Et merci d’être passé par ici, je suis ravi que ce petit script ait été utile.
        Il pourrait être largement optimisé, rien que de passer le $(this) dans une variable l’allègera pas mal.
        Et on pourrait imaginer faire un sous-sous-menu…

        Il faut que je retrouve le temps de faire des articles de ce type!

        Amusez-vous bien !

  8. 8
    Dan dit :

    Merci !
    Je cherchais ça depuis longtemps !
    Pas bidouillé, mais l script téléchargé fonctionne ok.
    Testé IE7 et 8 ok itou !
    Je poste ce MERCI parce que tu offres le téléchargement, c’est la moindre des choses de laisser un post ;-)

  9. 9
    Dan dit :

    oubli
    Quand tu fais des scripts à télécharger, évite de nommer des éléments (#header par exemple) que les développeurs utilisent souvent…. ça oblige à renommer et, pour les étourdis, ça peut foutre une belle pagaille ! !
    Je ne donne pas de leçons, juste un p’tit tuyau ;-)

  10. 10
    admin dit :

    Salut Dan, merci beaucoup pour ton retour. ça me fait plaisir de voir que des scripts, mêmes pas tous récents, peuvent servir. Par contre il y a clairement moyen de l’optimiser et même de faire mieux dans les animations.
    Je ne sais pas si tu as vu la réponse que j’ai faite un peu plus haut, mais je pense que ce petit script réalisé plus récemment est bien meilleur : http://test.goweb.fr/CHARTES/keolis/_integration/index.html
    Tu as tout à fait raison, il faut éviter d’utiliser ce genre d’id ou class ‘générique’. L’idéal étant sans doute d’ajouter des petits préfixes. J’ai toujours en projet de détailler et de partager de nouveaux scripts, mais faute de temps (l’excuse classique) je les mets au tiroir.
    Merci encore et bonne continuation !