Contenu principal
CSS Cooltips

Des tooltips animés en CSS

Aujourd’hui nous allons créer des tooltips en CSS.
Au programme, réaliser des triangles en CSS2, des coins arrondis en CSS3, des ombres en CSS2 et 3, des fonds dégradés en CSS3, des transitions CSS3 et l’utilisation des pseudo-éléments « :before » et « :after ».

But

Le but de ce tutoriel n’est pas vraiment de créer des tooltips utilisables en production (même s’ils fonctionnent, ils requièrent un marquage HTML supplémentaire et un autre détail va nous gêner si nous voulons utiliser les transitions CSS), mais plutôt d’apprendre à utiliser certaines propriétés CSS. En effet, d’autres techniques seraient plus adaptées (comme d’utiliser l’attribut « title » du lien avec le pseudo-élément « :after ». Cependant avec ce tutoriel, le rendu esthétique sera amélioré ;)

Faire un triangle en CSS

Faire un triangle en CSS n’est pas compliqué, il suffisait juste de trouver l’astuce. En plus, nous allons utiliser une seule balise HTML et une propriété CSS bien connue : border.
Prenons par exemple une balise <span> vide et voyons comment utiliser le CSS pour transformer un rectangle en triangle :

   
display: block;
width: 20px;
height: 20px;
border: #3F342A solid 10px;
display: block;
width: 0;
height: 0;
border: #3F342A solid 10px;
display: block;
width: 0;
height: 0;
border: transparent solid 10px;
border-top-color: #3F342A;

Nous utiliserons cette astuce pour faire la pointe sous les tooltips.

Marquage HTML

1

<a class="hastip" href="#">Hover me<span class="tip red">Rouge!</span></a>

Nous rajoutons juste la classe « hastip » aux liens qui bénéficieront d’un tooltip, ainsi qu’une balise <span> qui contiendra le texte de votre tooltip. La classe « tip » servira seulement à ne pas appliquer les CSS à des <span> qui se trouveraient à l’intérieur du lien. La classe « red » servira à choisir la couleur du tooltip.

CSS

Le lien :

1234

a.hastip {
	position: relative;
	text-decoration: none;
}

Le tooltip : mise en boite, positionnement et mise en forme du texte. Nous positionnons en absolu le tooltip qui fera 40px de haut (avec une seule ligne de texte).

0506070809101112131415161718

.tip {
	position: absolute;
	left: 0;
	top: -30px;
	z-index: 30;			/* A modifier selon les besoins */
	padding: 0 20px;
	width: auto;
	height: 40px;
	line-height: 40px;
	font-size: 18px;
	font-weight: bold;
	color: #191919;
	white-space: nowrap;	/* Pour garder tout le texte sur 1 seule ligne */
}

Le tooltip : bordures de 3 pixels et arrondis de 6 pixels.

19202122232425

.tip {
	border: solid 3px #191919;
	-webkit-border-radius:	6px;
	-moz-border-radius:	6px;
	-o-border-radius:	6px;
	border-radius:		6px;
}

Le tooltip : ombres. On rajoute du volume au texte avec 1 pixel noir (60% d’opacité) au-dessus et 1 pixel blanc au-dessous. De la même façon, nous rajoutons du volume au tooltip avec 1 pixel blanc (70% d’opacité) au-dessus (avec inset). Puis nous rajoutons une ombre autour du tooltip, décalée de 4 pixels vers le bas et un flou de 16 pixels.

26272829303132

.tip {
	text-shadow: 0 -1px 1px rgba(0,0,0,.6), 0 1px 1px rgba(255,255,255,1);
	-webkit-box-shadow:	inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
}

Le tooltip : le fond. Nous allons mettre une couleur de fond par défaut (blanc à 50% d’opacité) et rajouter un dégradé (noir, 27% d’opacité en haut et stoppé à 30% de la hauteur, vers 0% d’opacité en bas).

3334353637383940

.tip {
	background-color: rgba(255,255,255,.5);
	background-image:	-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,.27)), to(rgba(0,0,0,0)), color-stop(0.3, rgba(0,0,0,.27)));
	background-image:	-webkit-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:          -moz-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:	     -o-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:		linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
}

Le tooltip : transition CSS. Nous allons jouer sur l’opacité du tooltip et sa hauteur. Habituellement, le tooltip est par défaut dissimulé grâce à la propriété display: none; puis affiché avec display: block; au survol de la souris. Malheureusement, les effets désirés ne vont pas fonctionner si nous utilisons la propriété display, les transitions CSS seront bloquées. Il faudra donc nous passer de la propriété display hélas, et jouer sur l’opacité. Ce qui est le petit défaut de la méthode, car le tooltip, même invisible, reste « survolable » avec la souris.
N’oubliez pas que ces transitions CSS seront visibles seulement avec Firefox 4, Safari et Chrome. Pour Opera c’est pour bientôt je crois. Quand à IE… ***Je pouffe***

[update] Rajout de transform: scale(0); afin de réellement masquer le tooltip. Pour plus d’explications sur la transition CSS, voir le paragraphe suivant : survol.

404142434445464748495051

.tip {
	opacity: 0;
	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);					/* Fucking IE */
	-webkit-transform:	scale(0);
	-moz-transform:		scale(0);
	-o-transform:		scale(0);
	transform:		scale(0);
	-webkit-transition:	opacity .3s ease-in-out, top .3s ease-in-out, -webkit-transform 0s linear .4s;
	-moz-transition:	opacity .3s ease-in-out, top .3s ease-in-out, -moz-transform 0s linear .4s;
	-o-transition:		opacity .3s ease-in-out, top .3s ease-in-out, -o-transform 0s linear .4s;
	transition:		opacity .3s ease-in-out, top .3s ease-in-out, transform 0s linear .4s;
}

[update] Le tooltip : survol. Nous devons maintenant afficher le tooltip au survol de la souris. Comme prévu, nous allons mettre l’opacité à 1, faire monter le tooltip de 20px, mettre le scale() à 1, et animer tout ça avec des transitions CSS.

4546474849505152535455565758

.hastip:hover .tip, .hastip:active .tip {
	opacity: 1;
	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100);				/* Fucking IE */
	top: -60px;
	z-index: 40;
	-webkit-transform:	scale(1);
	-moz-transform:		scale(1);
	-o-transform:		scale(1);
	transform:		scale(1);
	-webkit-transition:	opacity .3s ease-in-out, top .3s ease-in-out;
	-moz-transition:	opacity .3s ease-in-out, top .3s ease-in-out;
	-o-transition:		opacity .3s ease-in-out, top .3s ease-in-out;
	transition:		opacity .3s ease-in-out, top .3s ease-in-out;
}

Vous remarquez que nous utilisons une deuxième fois une transition CSS et qu’il y a une différence entre les deux. En fait, la précédente va servir pour masquer le tooltip, alors que celle-ci sert pour le montrer.
Avec cette transition sur le :hover (pour montrer le tooltip) : nous animons uniquement opacity et top, mais pas scale(). Ainsi le tooltip apparait directement à la bonne taille et les animations sur opacity et top peuvent se dérouler.
Avec la transition sur l’état « normal » (pour masquer le tooltip) : nous animons également scale(), sinon scale() va passer directement à 0 dès que la souris quitte le lien, l’animation sur opacity et top ne se verrais alors pas. Pour cela, nous utilisons un retard : transform 0s linear .4s. transform correspond donc à scale(), qui va passer de 1 à 0. 0s est la durée de la transition : 0 secondes car on ne veut pas la voir dans notre cas, donc autant la mettre à zéro pour ne pas faire dépenser des ressources inutiles à l’ordinateur du visiteur. linear est la courbe de la transition, on met ce qu’on veut, de toute façon on ne verra pas l’animation sur scale(). 0.4s est le délais avant le début de l’animation. La durée des transitions sur opacity et top étant de 0.3s, celle sur scale() débutera une fois que le tooltip sera entièrement masqué.

Ce qui donne au final pour le tooltip :

050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

.tip {
	opacity: 0;
	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);					/* Fucking IE */
	position: absolute;
	left: 0;
	top: -30px;
	z-index: 30;
	padding: 0 20px;
	height: 40px;
	width: auto;
	border: solid 3px #191919;
	-webkit-border-radius:	6px;
	-moz-border-radius:	6px;
	-o-border-radius:	6px;
	border-radius:		6px;
	line-height: 40px;
	font-size: 18px;
	font-weight: bold;
	color: #191919;
	white-space: nowrap;
	text-shadow: 0 -1px 1px rgba(0,0,0,.6), 0 1px 1px rgba(255,255,255,1);
	background-color: rgba(255,255,255,.5);
	background-image:	-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,.27)), to(rgba(0,0,0,0)), color-stop(0.3, rgba(0,0,0,.27)));
	background-image:	-webkit-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:          -moz-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:	     -o-linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	background-image:		linear-gradient(top, rgba(0,0,0,.27) 30%, rgba(0,0,0,0));
	-webkit-box-shadow:	inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px rgba(255,255,255,.7), 0 4px 16px #191919;
	-webkit-transform:	scale(0);
	-moz-transform:		scale(0);
	-o-transform:		scale(0);
	transform:		scale(0);
	-webkit-transition:	opacity .3s ease-in-out,top .3s ease-in-out,-webkit-transform 0s linear .4s;
	-moz-transition:	opacity .3s ease-in-out,top .3s ease-in-out,-moz-transform 0s linear .4s;
	-o-transition:		opacity .3s ease-in-out,top .3s ease-in-out,-o-transform 0s linear .4s;
	transition:		opacity .3s ease-in-out,top .3s ease-in-out,transform 0s linear .4s;
}
.hastip:hover .tip, .hastip:active .tip {
	opacity: 1;
	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100);				/* Fucking IE */
	top: -60px;
	z-index: 40;
	-webkit-transform:	scale(1);
	-moz-transform:		scale(1);
	-o-transform:		scale(1);
	transform:		scale(1);
	-webkit-transition:	opacity .3s ease-in-out, top .3s ease-in-out;
	-moz-transition:	opacity .3s ease-in-out, top .3s ease-in-out;
	-o-transition:		opacity .3s ease-in-out, top .3s ease-in-out;
	transition:		opacity .3s ease-in-out, top .3s ease-in-out;
}

Maintenant, utilisons des triangles afin de créer la pointe sous le tooltip. Pour celà, il nous faudra deux triangles : un pour simuler la bordure, l’autre pour la pointe elle-même. Les pseudo-éléments :before et :after vont nous servir. Avec :before nous créons la bordure, et avec :after nous créons la pointe (car :after passera au-dessus de :before).

59606162636465666768697071727374757677

.tip:before, .tip:after {
	content: '';
	display: block;
	position: absolute;
	left: 20px;
	width: 0;
	height: 0;
}
.tip:before {
	border: solid 15px transparent;
	border-top-color: #191919;
	margin-left: -15px;
	bottom: -31px;
}
.tip:after {
	border: solid 12px transparent;
	margin-left: -12px;
	bottom: -24px;
}

La touche finale : la couleur

Au point où nous en sommes, nos tooltips sont transparents, avec bordure, ombres, et texte. Il ne reste plus qu’à rajouter la couleur aux tooltips et aux pointes. Cette couleur sera modifiable selon la classe attribuée au tooltip.

7879808182838485868788

.red {
	text-shadow: 0 -1px 1px #600, 0 1px 1px #f00;
	background-color: #b00;
	-webkit-box-shadow:	inset 0 1px 1px #d00, 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px #d00, 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px #d00, 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px #d00, 0 4px 16px #191919;
}
.red:after {
	border-top-color: #b00;
}

Allez, tant que nous y sommes, rajoutons d’autres couleurs :)

089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121

.green {
	text-shadow: 0 -1px 1px #060, 0 1px 1px #0f0;
	background-color: #0b0;
	-webkit-box-shadow:	inset 0 1px 1px #0d0, 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px #0d0, 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px #0d0, 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px #0d0, 0 4px 16px #191919;
}
.green:after {
	border-top-color: #0b0;
}
.blue {
	text-shadow: 0 -1px 1px #066, 0 1px 1px #0ff;
	background-color: #0cf;
	-webkit-box-shadow:	inset 0 1px 1px #0dd, 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px #0dd, 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px #0dd, 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px #0dd, 0 4px 16px #191919;
}
.blue:after {
	border-top-color: #0cf;
}
.grey {
	text-shadow: 0 -1px 1px #666, 0 1px 1px #fff;
	background-color: #bbb;
	-webkit-box-shadow:	inset 0 1px 1px #ddd, 0 4px 16px #191919;
	-moz-box-shadow:	inset 0 1px 1px #ddd, 0 4px 16px #191919;
	-o-box-shadow:		inset 0 1px 1px #ddd, 0 4px 16px #191919;
	box-shadow:		inset 0 1px 1px #ddd, 0 4px 16px #191919;
}
.grey:after {
	border-top-color: #bbb;
}

Bien, dites moi ce que vous pensez de tout ça dans les commentaires.

[update] Article originalement publié le 29 janvier 2011.