L'animation et le survol souris avec CSS3 ou jQuery
Les ergonomes s'accordent à dire qu'un des moyens pour informer l'utilisateur qu'il peut interagir avec un élément est de changer son apparence au survol de la souris. On peut réaliser cela rapidement en CSS avec plus ou moins d'effets et de complexité ou utiliser JavaScript pour faire quelque chose de plus poussé. Il va être question ici d'étudier une autre possibilité du survol de la souris qui consiste en l'apparition et l'animation d'éléments autres que l'objet survolé. En outre cet article va vous présenter la manière de gérer des menus contextuels en passant par jQuery et même CSS3.
Les bases du survol en CSS
Petit rappel donc sur la possibilité de changer le style d'un élément au survol de la souris grâce aux CSS en utilisant la pseudo-class :hover. Celle-ci est compatible IE7+ et autres navigateurs sur toutes balises HTML survolable et seulement fonctionnelle sur la balise <a> dans le cas d'une utilisation IE6- (comprendre ici IE6 et versions inférieures). Comme toute pseudo-class elle ne fonctionne pas dans l'attribut HTML style.
Exemple de menu simple avec :hover
HTML dans <body>
<nav class="menu"> <div> <a href="" title="">Navigateurs</a> <ul> <li><a href="" title="">Chrome</a></li> <li><a href="" title="">Firefox</a></li> <li><a href="" title="">IE</a></li> </ul> </div> <div> <a href="" title="">OS</a> <ul> <li><a href="" title="">Windows</a></li> <li><a href="" title="">Linux</a></li> <li><a href="" title="">Mac</a></li> </ul> </div> <div> <a href="" title="">Appareils</a> <ul> <li><a href="" title="">PC/MAC</a></li> <li><a href="" title="">Smartphone</a></li> </ul> </div> </nav>
CSS avec link
/** On prévoit de ne pas laisser écouler les flottants hors du menu. **/ .menu:after { content: ""; /* Génération d'un élément après .menu. */ display: block; /* Donner un comportement à l'élément. */ clear: both; /* Pas de flottement à gauche ou à droite. */ } /** On arrondit la gauche et la droite du menu. **/ .menu div:first-child { /* Gauche correspond au premier élément. */ border-top-left-radius: 8px; border-bottom-left-radius: 8px; } .menu div:last-child { /* Droite correspond au dernier élément. */ border-top-right-radius: 8px; border-bottom-right-radius: 8px; } .menu div { position: relative; /* Définition de <div> comme référence de positionnement. */ float: left; /* display: inline-block; fait l'affaire si pas de support pour IE7. */ padding: 8px; background-color: #bbbbbb; background: linear-gradient(to bottom, #dddddd, #bbbbbb); /* Ajouter préfixes propriétaires -webkit-, -o-, etc... */ } .menu div ul { position: absolute; /* Placer l'élément par rapport à son parent et hors du flux. */ left: 0; display: none; /* Cacher l'élément. */ z-index: 7; margin-left: 0; background-color: #cccccc; } /** Utilisation de :hover pour afficher les sous-liens au survol de la souris. **/ .menu div:hover ul { display: block; } .menu li { list-style: none; }
Un peu d'animation au survol souris avec transition:
Il faut faire attention avec la propriété transition: CSS3. Cette propriété est triviale pour de l'animation au survol de la souris sur un élément pour changer sa propre apparence et se passer de JavaScript. Cependant, dans le cas de l'exemple précédent, ou le hover modifie l'apparence d'un autre élément que celui survolé, il faut garder à l'esprit plusieurs choses :
- La transition sera bloquée si l'objet passe de display: none; vers un autre affichage.
- La transition ne fonctionnera pas vers une valeur automatique (height: auto;).
- La transition ne fonctionnera pas sans ses préfixes propriétaires (-webkit-, -o-, -moz-...) à ce jour.
Modifions la CSS du code précédent pour prendre en compte ces remarques. Il va falloir cacher le menu sans utiliser display: none;. On va faire appel à heigh: et overflow:
/*** ... ***/ .menu div ul { /*** ... ***/ /* display: none; <= On retire display: none;. */ /*** ... ***/ /** On simule le display: none; d'une autre façon. **/ height: 0; padding: 0; overflow: hidden; /** Au survol de l'élément, on changera sa hauteur avec transition pendant 0.5s. **/ transition: height 0.5s; /* Ajouter -webkit-, -o-, etc... */ } .menu div:hover ul { /* display: block; <= Plus besoin de display:block;. */ height: 80px; /* Obligation de forcer la valeur de la propriété de transition sur autre que auto. */ } /*** ... ***/ /** On remplace la perte padding de <ul> par des marges sur les <li>. **/ .menu li { margin: 0 8px 0 8px; } .menu li:first-child { margin-top: 8px; } .menu li:last-child { margin-bottom: 8px; }
On note un changement pour le troisième élément <ul> puisque sa hauteur a été imposée. Il faudrait donc régler toutes les hauteurs en fonction du nombre d'élément <i> (pas très pratique...).
Animation et survol avec JavaScript et jQuery
Nous allons voir ici comment produire l'effet CSS3 précédent en JavaScript avec la librairie jQuery. Cela permettra aux navigateurs ne supportant pas la propriété CSS3 transition: de tout de même afficher cette animation. Nous allons dans un premier temps conserver la CSS précédente, mais couper la transition CSS3.
/*** ... ***/ .menu div ul { /*** ... ***/ /* transition: height 0.5s; <= Sera géré en JavaScript. */ } .menu div:hover ul { /* height: 80px; <= Peut repasser en automatique. */ height: auto; } /*** ... ***/
Equivalence simple
C'est parti pour un code JavaScript équivalent à transition:. N'oubliez pas d'inclure jQuery.
$(document).ready(function () { // Si le script n'est pas en pied de page, on va attendre le chargement complet du DOM. /* Pour chacune des 3 <div> du menu, on va... */ $(".menu div").each(function () { var $ul = $(this).find("ul"); // ...rendre accessible les variables dans les deux parties de hover... /* ...et initialiser un comportement au passage/retrait de la souris. */ $(this).hover(function () { /* Pour le survol on... */ var tempHeight = $ul.css("height", "auto").height(); // ...garde en mémoire la taille réelle de <ul> si affichée... $ul .height(0) // ...repart d'une hauteur de zéro... .stop() // ...stop l'éventuelle animation de fermeture... .animate({ height: tempHeight.toString() }, 500); // ...et on déclenche l'animation d'ouverture. }, function () { /* Pour le retrait on... */ $ul .stop() // ...stop l'éventuelle animation d'ouverture... .animate({ height: "0" }, 500); // ...et on déclenche l'animation de fermeture. }); }); });
Effectuer l'animation avec plus de condition qu'un simple survol
Afin d'éviter l'ouverture intempestive de votre menu au passage de la souris au-dessus de celui-ci vous avez plusieurs alternatives qui s'offrent à vous. Je vais en fournir deux ici, mais libre à vous de trouver d'autres solutions.
N'effectuer le hover que si la souris reste plus d'un certain temps
$(document).ready(function () { $(".menu div").each(function () { var $ul = $(this).find("ul"), tempTimer; // On crée une variable pour manipuler le délai dans les deux parties du hover. $(this).hover(function () { var tempHeight = $ul.css("height", "auto").height(); $ul.height(0); tempTimer = setTimeout(function () { // On déclenche l'animation avec un temps de latence. $ul .stop() .animate({ height: tempHeight.toString() }, 500); }, 1000); // On règle l'équivalence que l'on juge adapté. J'ai mis 1 seconde pour l'exemple. }, function () { clearTimeout(tempTimer); // Si on sort avant la fin du délai, on n'effectuera pas l'animation. $ul .stop() .animate({ height: "0" }, 500); }); }); });
En passant rapidement la souris, on ne risque pas de déclencher d'ouverture. J'ai excessivement exagéré le délai à une seconde pour le mettre en évidence.
N'effectuer le hover que si la souris ne bouge plus
$(document).ready(function () { /** On permet d'accéder aux valeurs réelles de la souris à tout moment avec : pour x : $(".menu div").data("x"), pour y : $(".menu div").data("y"). **/ $(".menu div").mousemove(function (e) { $.data(this, "x", e.pageX); // On met a jour la souris en x. $.data(this, "y", e.pageY); // On met a jour la souris en y. }).data("x", 0).data("y", 0) // On initialise les valeurs. .each(function () { var $this = $(this), $ul = $this.find("ul"), tempTimer, tempX, tempY; // Variables accessibles dans les deux parties de hover. $this.hover(function () { var tempHeight = $ul.css("height", "auto").height(); $ul.height(0); tempTimer = setInterval(function () { // On vérifie à intervalle régulier... if (tempX == $this.data("x") && tempY == $this.data("y")) { // ...si la souris ne bouge plus. clearInterval(tempTimer); // Alors on arrête la vérification et on ouvre le menu. $ul .stop() .animate({ height: tempHeight.toString() }, 500); } tempX = $this.data("x"); // Noter la précédente position en x de la souris. tempY = $this.data("y"); // Noter la précédente position en y de la souris. }, 50); // Temps entre chaque vérification de position. }, function () { clearInterval(tempTimer); // Si on quitte l'objet, on arrête également la vérification. $ul .stop() .animate({ height: "0" }, 500); }); }); });
Tant que votre souris sera en mouvement sur le menu, le menu ne se dépliera pas. On peut également remplacer l'égalité stricte par une fourchette de valeur afin d'élargir ce que l'on considère comme une souris fixe.
D'autres techniques
Si vous aussi vous avez des tips d'utilisation du survol souris n'hésitez pas à les partager en commentaire.
4 Commentaires
Choisir un Avatar depuis une url
Adresse : (64px x 64px)ou Changer la couleur de fond
et Choisir un Avatar dans la liste
Votre commentaire a été ajouter ci-dessous ! Si vous désirez le supprimer ultérieurement, servez vous du code suivant :
Les commentaires sont actuellement affiché du plus rescent au plus ancien. Vous pouvez inverser l'ordre en cliquant ci-dessous :
Vraiment, un grand merci pour toutes ces explication !
J'en avais besoin histoire de remettre du tri dans mes connaissance en CSS3 et Jquery ...
CSS3 est beaucoup plus utile que je le pensais (et jquery en fin de compte du vrai bidouillage...)
Merci Encore !
Je trouve ce commentaire pertinent ?
Merci Bruno pour ton aide rapide !!
Je tente de me débrouiler avec tes conseils, et je te dis si je réussis !
Bonne journée !
YB
Je trouve ce commentaire pertinent ?
Bonsoir yb,
Merci pour ta lecture et ton retour appréciable.
Oui, le soucis vient de la fonction hover(). Cette fonction rassemble les fonctions mouseover() et mouseout(). Le problème ici c'est que tu cibles la balise ".titre" avec hover(). Forte heureusement, quand tu entres ça s'ouvre (ligne 7) mais quand tu sors ça se ferme (ligne 15). Tu veux bien que ça s'ouvre au survole, mais pas quand ça part !
Dans un premier temps je te propose de remplacer hover() par mouseover() pour ne gérer que le survole (http://api.jquery.com/mouseover/).
La fermeture, je te propose de la gérer avec l'évènement mouseout() (http://api.jquery.com/mouseout/) que tu ne vas pas associer à ".titre" mais plutôt à ".menu" de sorte que « tant que l'utilisateur ne sort pas de la zone de menu, les images ne disparaissent pas ».
Je me permets de te donner la solution (car il y a un petit détail que tu ne pourras pas deviner) mais essaie de développer ça par toi même d'après mes directives avant de donner ta langue au chat (solution : http://jsfiddle.net/h7HS8/14/).
Une autre solution consiste à mettre un délai autour de la fermeture de ton image après le mouseout de ".titre" et d'annuler se délai au mouseover de ton image. Sur le mouseout de ton image tu mettras également la fermeture de celle-ci. Il faut un délai raisonnable pour avoir le temps d'atteindre l'image mais pour ne pas avoir l'impression qu'il s'écoule trop de temps après avoir quitté ".titre".
Je trouve ce commentaire pertinent ?
Bonjour Bruno ,
Je te remercie tout d'abord pour tes articles qui sont très instructifs et didactiques ; Je suis ce qu'on appelle communément un NOOB, et pourtant grâce à toi, je comprends ce que je code !
Ou presque, car j'ai un petit soucis.
je te mets le lien pour que tu puisses voir ce que je tente de faire : http://jsfiddle.net/h7HS8/10/
Comme tu vas pouvoir le constater, j'ai copié ton tuto pour afficher des images au survol de ma souris. le problème et que, une fois affichées, elles ne restent pas en place lorsque je déplace ma souris. L'animation de fermeture se lance.
Voilà, je ma permet de te demander de jeter un œil car je pense que pour toi le problème sera évident. Merci pour tout !
Je trouve ce commentaire pertinent ?
Je trouve ce commentaire pertinent ?