Il y a quelques temps déjà, Lea Verou proposait d’utiliser la propriété max-height afin d’effectuer des animations sur un élément sans toucher à la propriété height. Avec une petite adaptation, il est possible de créer un menu déroulant au survol avec un petit délai créé grâce à la propriété CSS 3 transition.

Démonstration

Le sujet du menu déroulant est très sensible. De par sa nature, il est bien souvent considéré comme peu ergonomique, inaccessible et dans certains cas il est l’illustration d’un mauvais travail sur l’arborescence d’un site. Bref, l’article ici présente une démonstration en CSS, non une étude approfondie des tenants et aboutissants d’un menu déroulant.

Un bout de HTML

Le code HTML est assez classique, il s’agit d’imbriquer des listes non-ordonnées.

<ul id="menu">
	<li><a href="#">Menu 1</a>
		<ul>
			<li><a href="#">Level 1.1</a></li>
			<li><a href="#">Level 1.2</a></li>
		</ul>
	</li><li><a href="#">Menu 2</a>
		<ul>
			<li><a href="#">Level 2.1</a></li>
			<li><a href="#">Level 2.2</a></li>
			<li><a href="#">Level 2.3</a></li>
			<li><a href="#">Level 2.4</a></li>
		</ul>
	</li><li><a href="#">Menu 3</a>
		<ul>
			<li><a href="#">Level 3.1</a></li>
			<li><a href="#">Level 3.2</a></li>
			<li><a href="#">Level 3.3</a></li>
		</ul>
	</li>
</ul>

Les chevrons fermants et ouvrants des li de premier niveau sont collés pour éviter le white-space. (pour en savoir plus : Article sur display inline-block – Creative Juiz)

Place au CSS

Le menu déroulant terminé

Je ne vais pas détailler ici la partie sur la création d’un menu horizontal. Je vous invite à lire le tutoriel « Créer un menu horizontal centré » qui reprend une partie des explications.

/* partie positionnement et déco */
#menu a { 
	display:block; 
	color: #fff; 
	text-decoration:none;
}
#menu > li,
#menu > li li {
	position: relative;
	display:inline-block;
	width: 110px;
	padding: 6px 15px;
	background-color: #777;
	background-image: linear-gradient(#aaa, #888 50%, #777 50%,#999);
}
#menu > li li { background: transparent none; }
#menu > li li a { color: #444; }
#menu > li li:hover { background:#eee; }
#menu > li:first-child {
	border-right: 1px solid #777;
	border-radius: 8px 0 0 8px;
}
#menu > li + li {
	border-left: 1px solid #aaa;
	border-right: 1px solid #777;
}
#menu > li:last-child {
	border-right: 0;
	border-left: 1px solid #aaa;
	border-radius: 0 8px 8px 0 ;
}
#menu > li:hover {
	background-color: #999;
	background-image: linear-gradient(#ccc, #aaa 50%, #999 50%,#bbb);
}
/* (presque) fin de la partie positionnement/déco */
/* dans cette déclaration, on fixe le max-height */
#menu ul {
	position: absolute;
	top: 2em; left: 0;
	max-height:0em;	
	margin: 0; padding: 0;
	background-color: #ddd;
	background-image: linear-gradient(#fff,#ddd);
	overflow: hidden;
	transition: 1s max-height 0.3s;
	border-radius: 0 0 8px 8px;
}
/* ici on change la valeur de max-height au :hover */
#menu > li:hover ul {
	/* à adapter, le minimum est le meilleur mais voyez large 😉 */
	max-height: 13em;
}

Concentrons nous sur l’utilisation de max-height et transition pour effectuer notre animation.
Lorsqu’on fixe, ligne 41, la valeur de max-height à 0, on lui dit clairement : ta hauteur maximale sera nulle (l’élément ne sera pas visible).
Pour que cela fonctionne, il faut coupler cette propriété à un débordement caché (ligne 45).

Ligne 46, nous prévoyons une transition sur la propriété max-height que nous allons faire varier par la suite. Cette transition se déroulera sur 1s et se déclanchera 0.3s après le survol de l’élément, et ce pour le confort de l’utilisateur. (ça évite d’avoir des sous-menus qui se déroulent dès qu’on effleure le menu)

Enfin, au survol de l’élément li, nous faisons varier la hauteur maximale du sous-menu (ligne 52).
En prévoyant large (mais pas trop), vous créerez un effet de délai avant l’animation de repliement. Ici 8em seraient suffisant, j’en prévoit 13.

Démonstration

N’hésitez pas à commenter si vous avez des zones floues 😉
Amusez-vous bien !