:: [ xhtml / css ] Création d’un menu horizontal avec sous-menu déroulant ::
[MISE A JOUR 21.11.06] Tuto à reprendre complètement pour cause de bug.
Pour ce menu déroulant, nous allons faire en sorte qu’il soit compatible xhtml 1.0 strict, tout du moins pour le fichier html.
En effet nous allons être obligé d’utiliser une astuce que les normes xhtml ne reconnaissent pas, cela pour que le menu fonctionne sous IE 6 et inférieur.
Vous aurez besoin d’un menu horizontal pour commencer, vous pouvez reprendre celui de mon précédent tuto
« Création d’un menu horizontal », en tout cas ça sera notre point de départ ici.
Nous voici donc avec notre code de départ :
<html>
<head>
<style type="text/css">
div#liste_menu ul li { float: left; list-style-type: none; font-family: Verdana; font-size: 11px; font-weight: bold; text-align: center; }
div#liste_menu ul li a { display: block; background-image: url('bouton.gif'); width: 116px; height: 31px; background-repeat: no-repeat; color: #000000; text-decoration: none; padding-top: 3px;}
div#liste_menu ul li a:hover { text-decoration: none; color: red;}
</style>
</head>
<body>
<div id="liste_menu">
<ul>
<li><a href="#">Menu 01</a></li>
<li><a href="#">Menu 02</a></li>
<li><a href="#">Menu 03</a></li>
<li><a href="#">Menu 04</a></li>
</ul>
</div>
</body>
</html>
1°) Commençons par rajouter du code dans le body.
Pour des raisons de clarté nous allons faire ce menu déroulant que sur le premier onglet,à savoir "menu 01".
Reprennez donc le code suivant à mettre à la place du code présent dans le
body:
<div id="liste_menu">
<ul>
<li><a href="#">Menu 01</a>
<ul>
<li><a href="1.do">sous menu 01</a></li>
<li><a href="2.do">sous menu 02</a></li>
<li><a href="3.do">sous menu 03</a></li>
<li><a href="4.do">sous menu 04</a></li>
</ul>
</li>
<li><a href="#">Menu 02</a></li>
<li><a href="#">Menu 03</a></li>
<li><a href="#">Menu 04</a></li>
</ul>
</div>
2°) A cet instant nous avons un sous menu horizontal auquel a été appliqué les règles css du menu.
Nous le voulons vertical et sans les boutons en arrière plan.
Grâce à l'héritage des css nous n'avons pas besoin de remettre toute les propriétés de texte par exemple, juste désactivé celle qui nous gène.
Ici c'est le
float: left; que nous passons en
float: none; dans une nouvelle ligne de css qui cible la seconde liste.
div#liste_menu ul li ul li { float: none; }
3°) Vous remarqué un décalage, corrigé cela en rajoutant une propriété
margin-left négative :
div#liste_menu ul li ul li { float: none; margin-left: -40px; }
4°) Passons maintenant aux liens.
Le
div#liste_menu ul li ul li a:link et le
div#liste_menu ul li ul li a:visited devant être identique nous allons les coupler pour gagner une ligne en
div#liste_menu ul li ul li a:link, div#liste_menu ul li ul li a:visited.
Rajoutez donc les lignes de css suivantes :
div#liste_menu ul li ul li a { }
div#liste_menu ul li ul li a:link, div#liste_menu ul li ul li a:visited { }
div#liste_menu ul li ul li a:hover { }
5°) Ajoutons les propriétés maintenant.
Nous allons transformer la balise
<a> en élément block grâce au
display pour lui donner une dimension en px, retirer l'image de fond et ajouter une couleur de fond.
div#liste_menu ul li ul li a { display: block; width: 116px; height: 15px; background-image: none; background-color: #EEEEEE; }
6°) Dans la ligne
div#liste_menu ul li ul li a:link, div#liste_menu ul li ul li a:visited on ne mettra rien, enfin on ne changera rien des propriétés acquises par l'héritage.
Si vous le désirez, vous pouvez changer de police, de taille de police, de couleur etc grâce aux propiétés du
font que vous retrouverez un peu plus haut dans ce tuto.
Laissons donc la ligne vide :
div#liste_menu ul li ul li a:link, div#liste_menu ul li ul li a:visited { }
Vous pouvez la retirer mais pour des raisons pédagogique je l'a laisse.
7°)Ensuite, l'attribut
a:hover à définir.
On enlève l'image de fond, on rajoute une couleur à la place et on grossit le texte pour qu'au passage de la souris on ait un petit effet de loupe.
Vous obtenez la ligne suivante:
div#liste_menu ul li ul li a:hover { color: #FFFFFF; background-image: none; background-color: #FF9900; font-size: 12px; }
8°)Notre sous-menu est maintenant fait, reste qu'à le faire disparaitre et apparaitre au passage de la souris.
Pour ce faire, masquons le sous menu lorsqu'il n'est pas survolé; rajoutez cette ligne que nous mettrons au tout début du css :
body div#liste_menu ul li ul { display: none; }
9°)Puis il nous faut le faire réapparaitre lorsque le menu est survolé, cela se fait grâce à cette ligne :
div#liste_menu ul li:hover ul, div#liste_menu ul li ul:hover { display: block; }
Petite explication :
-
div#liste_menu ul li:hover ul fait en sorte d'afficher le sous-menu lorsque le menu est survolé.
-
div#liste_menu ul li ul:hover fait en sorte de garder l'affichage lorque nous quittons le menu pour naviguer dans le sous-menu.
10°)Ca y est notre menu fonctionne ! Mais pas sous IE6 et inférieur ! Or ce navigateur reste encore le plus utilisé, nous devons donc faire en sorte que cela fonctionne.
Pour l'instant on va laisser de côté le critère "compatible xhtml 1.0 strict", mais ne vous inquiètez pas, au final nos fichier html le sera !
C'est maintenant qu'une astuce arrive ! Elle n'est pas du tout de moi, j'aurais été incapable de la mettre au point !
Tout est expliqué à cette adresse :
http://http://www.xs4all.nl/~peterned/hovercraft.html.
En résumé, IE6 et inférieur ne comprend pas l'attribut
:hover sur une autre balise que
<a>, nous allons donc faire en sorte qu'il l'accepte.
Pour cela, créez un fichier nommé
csshover.htc.
Ouvrez le et insérez ce code :
<attach event="ondocumentready" handler="parseStylesheets" />
<script>
/**
* Whatever:hover - V1.42.060206 - hover & active
* ------------------------------------------------------------
* (c) 2005 - Peter Nederlof
* Peterned - http://www.xs4all.nl/~peterned/
* License - http://creativecommons.org/licenses/LGPL/2.1/
*
* Whatever:hover is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Whatever:hover is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Credits and thanks to:
* Arnoud Berendsen, Martin Reurings, Robert Hanson
*
* howto: body { behavior:url("csshover.htc"); }
* ------------------------------------------------------------
*/
var csshoverReg = /(^|\s)(([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active)/i,
currentSheet, doc = window.document, hoverEvents = [], activators = {
onhover:{on:'onmouseover', off:'onmouseout'},
onactive:{on:'onmousedown', off:'onmouseup'}
}
function parseStylesheets() {
if(!/MSIE (5|6)/.test(navigator.userAgent)) return;
window.attachEvent('onunload', unhookHoverEvents);
var sheets = doc.styleSheets, l = sheets.length;
for(var i=0; i<l; i++)
parseStylesheet(sheets[i]);
}
function parseStylesheet(sheet) {
if(sheet.imports) {
try {
var imports = sheet.imports, l = imports.length;
for(var i=0; i<l; i++) parseStylesheet(sheet.imports[i]);
} catch(securityException){}
}
try {
var rules = (currentSheet = sheet).rules, l = rules.length;
for(var j=0; j<l; j++) parseCSSRule(rules[j]);
} catch(securityException){}
}
function parseCSSRule(rule) {
var select = rule.selectorText, style = rule.style.cssText;
if(!csshoverReg.test(select) || !style) return;
var pseudo = select.replace(/[^:]+:([a-z-]+).*/i, 'on$1');
var newSelect = select.replace(/(\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi, '.$2' + pseudo);
var className = (/\.([a-z0-9_-]*on(hover|active))/i).exec(newSelect)[1];
var affected = select.replace(/:(hover|active).*$/, '');
var elements = getElementsBySelect(affected);
if(elements.length == 0) return;
currentSheet.addRule(newSelect, style);
for(var i=0; i<elements.length; i++)
new HoverElement(elements[i], className, activators[pseudo]);
}
function HoverElement(node, className, events) {
if(!node.hovers) node.hovers = {};
if(node.hovers[className]) return;
node.hovers[className] = true;
hookHoverEvent(node, events.on, function() { node.className += ' ' + className; });
hookHoverEvent(node, events.off, function() { node.className = node.className.replace(new RegExp('\\s+'+className, 'g'),''); });
}
function hookHoverEvent(node, type, handler) {
node.attachEvent(type, handler);
hoverEvents[hoverEvents.length] = {
node:node, type:type, handler:handler
};
}
function unhookHoverEvents() {
for(var e,i=0; i<hoverEvents.length; i++) {
e = hoverEvents[i];
e.node.detachEvent(e.type, e.handler);
}
}
function getElementsBySelect(rule) {
var parts, nodes = [doc];
parts = rule.split(' ');
for(var i=0; i<parts.length; i++) {
nodes = getSelectedNodes(parts[i], nodes);
} return nodes;
}
function getSelectedNodes(select, elements) {
var result, node, nodes = [];
var identify = (/\#([a-z0-9_-]+)/i).exec(select);
if(identify) {
var element = doc.getElementById(identify[1]);
return element? [element]:nodes;
}
var classname = (/\.([a-z0-9_-]+)/i).exec(select);
var tagName = select.replace(/(\.|\#|\:)[a-z0-9_-]+/i, '');
var classReg = classname? new RegExp('\\b' + classname[1] + '\\b'):false;
for(var i=0; i<elements.length; i++) {
result = tagName? elements[i].all.tags(tagName):elements[i].all;
for(var j=0; j<result.length; j++) {
node = result[j];
if(classReg && !classReg.test(node.className)) continue;
nodes[nodes.length] = node;
}
}
return nodes;
}
</script>
11°)Vous pouvez fermer ce fichier et retournez dans le fichier html.
Maintenant il faut appeler ce fichier .htc.
Créez pour cela une nouvelle ligne css que vous mettrez en tout premier, c'est à dire juste en dessous du
<style type="text/css">.
body { behavior: url(csshover.htc); }
12°)Voilà, notre menu est censé fonctionner sous internet explorer. Vous pouvez peut être avoir une alerte de ça part en haut de la fenêtre, normal car ce qu'il y a dans le fichier
csshover.htc est du javascript, reconnu comme potentiellement mais ici rien à craindre vous pouvez donc autoriser le contenu.
13°)Nous y voilà donc ! Votre menu est totalement fonctionnel !
Cependant on peut l'optimiser facilement !
Que faire de plus ?
C'est de l'ordre esthétique mais c'est plus joli ainsi.
Lorsque vous survolez le menu, le sous-menu s'affiche et l'image du menu change.
Quand vous commencez à naviguer dans le sous-menu, l'image du menu redevient celle d'origine, pas terrible ça non ? Vaudrait mieux que l'image de survol reste quand on navigue ...
Nous allons remédiez à cela !
14°)Alors, nous allons modifier un brin le contenu du
body.
Nous avons une architecture comme cela:
<a href="#">Menu 01</a>
<ul>
<li><a href="1.do">sous menu 01</a></li>
<li><a href="2.do">sous menu 02</a></li>
<li><a href="3.do">sous menu 03</a></li>
<li><a href="4.do">sous menu 04</a></li>
</ul>
Rajoutez une balise
<div> juste avant la balise
<a href="#"> ainsi qu'une balise
</div> juste après le
</ul>.
Rajoutez aussi une
class="t" dans la balise
<a href="#">.
Au final vous avez cela à la place du précédent code :
<div>
<a href="#" class="t">Menu 01</a>
<ul>
<li><a href="1.do">sous menu 01</a></li>
<li><a href="2.do">sous menu 02</a></li>
<li><a href="3.do">sous menu 03</a></li>
<li><a href="4.do">sous menu 04</a></li>
</ul>
</div>
15°)Une légère modification est à faire dans une ligne existante dans la partie css.
Repérez la ligne suivante :
div#liste_menu ul li a:hover { text-decoration: none; color: red; background-image: url('bouton_on.gif'); }
Remplacez-là par celle-ci :
div#liste_menu ul li div:hover a.t { text-decoration: none; color: red; background-image: url('bouton_on.gif'); }
:://::\\:: Résumé :://::\\::
Nous avons donc le fichier html et son css suivant :
<html>
<head>
<style type="text/css">
body { behavior: url(csshover.htc); }
body div#liste_menu ul li ul { display: none; }
div#liste_menu ul li { float: left; list-style-type: none; font-family: Verdana; font-size: 11px; font-weight: bold; text-align: center; }
div#liste_menu ul li a { display: block; background-image: url('bouton.gif'); width: 116px; height: 31px; background-repeat: no-repeat; color: #000000; text-decoration: none; padding-top: 3px;}
div#liste_menu ul li div:hover a.t { text-decoration: none; color: red; background-image: url('bouton_on.gif'); }
div#liste_menu ul li ul li { margin-left: -40px; float: none; }
div#liste_menu ul li ul li a { display: block; background-image: none; background-color: #EEEEEE; width: 116px; height: 15px; }
div#liste_menu ul li ul li a:link, div#liste_menu ul li ul li a:visited { }
div#liste_menu ul li ul li a:hover { color: #FFFFFF; background-image: none; background-color: #FF9900; font-size: 12px; }
div#liste_menu ul li:hover ul, div#liste_menu ul li ul:hover { display: block; }
</style>
</head>
<body>
<div id="liste_menu">
<ul>
<li>
<div>
<a href="#" class="t">Menu 01</a>
<ul>
<li><a href="1.do">sous menu 01</a></li>
<li><a href="2.do">sous menu 02</a></li>
<li><a href="3.do">sous menu 03</a></li>
<li><a href="4.do">sous menu 04</a></li>
</ul>
</div>
</li>
</ul>
</div>
</body>
</html>
Il vous suffit de faire un simple copier/coller pour rajouter des onglets à votre menu.
Nous avons aussi le fichier
csshover.htc que vous reprendrez à l'étape 10.
Reste à aborder la compatibilité xhtml 1.0 strictA suivre : "Création d'un menu horizontal déroulant avec sous-menu multiples".
:: corven ::