L'intérêt des transitions CSS est de s'affranchir de JavaScript pour dynamiser nos pages Web. Cependant, il peut s'avérer nécessaire d'utiliser ce langage pour effectuer certaines manipulations. Par exemple, comment indiquer au navigateur qu'il doit lancer la transition de tel élément lorsque l'on clique sur tel bouton ? En CSS, ce n'est tout simplement pas possible…
JavaScript va donc nous offrir plus de possibilités avec les transitions, tout ceci avec une simplicité déconcertante !
Vingt mille lieues sous les mers
Pour vous donner un exemple des possibilités qui nous sont offertes, je vous propose de vous prendre pour le capitaine Nemo ! Nous simulerons une sorte de sous-marin pour voir l'océan à travers un hublot…
Pour cela, nous allons avoir besoin de trois images :
Voici donc ce que je vous propose de faire. Notre page contiendra deux
<div>. La première aura pour fond notre océan et contiendra une image : le hublot.
La seconde
<div> en contiendra huit autres : une pour chaque flèche de notre tableau de bord.
Ce dernier se comportera de cette façon : quand la souris passera sur une flèche, la vue que nous aurons de l'océan à travers le hublot se déplacera dans la direction indiquée.
Ça peut vous paraître flou pour l'instant, mais je vous assure que c'est très simple.
Les codes HTML et CSS
Vous ne devriez pas avoir de mal à comprendre le code HTML de ce mini projet :
Code : HTML 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | <!DOCTYPE html>
<html>
<head>
<title>Vingt mille lieues sous les mers</title>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript">
window.onload=function()
{
//On placera notre code JS ici.
};
</script>
</head>
<body>
<div id="ocean">
<img src="hublot.png" alt="Hublot"/>
</div>
<div id="controls">
<div id="fleche_hg"></div>
<div id="fleche_h"></div>
<div id="fleche_hd"></div>
<div id="fleche_g"></div>
<div id="fleche_d"></div>
<div id="fleche_bg"></div>
<div id="fleche_b"></div>
<div id="fleche_bd"></div>
</div>
<h1>Passez la souris sur les flèches !</h1>
</body>
</html>
|
Tous les éléments de notre page sont mis en place, il ne nous reste qu'à styliser tout ça.
Nous ne nous occuperons du code JavaScript qu'à la fin, une fois que tout sera bien fixé dans notre code CSS.
Commençons donc par traiter ce qu'il y a de plus facile : je propose déjà de colorer le fond de notre page en gris, parce que le blanc est un peu agressif. Centrons également l'instruction «
Passez la souris sur les flèches ! » pour faire plus propre.
Code : CSS | body
{
background-color: #a5a5a5;
}
h1
{
text-align: center;
}
|
Bon, passons aux choses sérieuses avec l'océan à proprement parler.
Nous devons le mettre aux mêmes dimensions que l'image du hublot. Pour que ce soit plus joli, nous pouvons également le centrer et lui ajouter une petite bordure. N'oublions également pas de lui appliquer notre image de fond que nous allons d'ailleurs centrer.
Rappelons-nous le but de l'exercice tout de même : utiliser les transitions. Pour simuler l'exploration des fonds marins, nous modifierons la position de l'arrière-plan, tout simplement !
Code : CSS 1
2
3
4
5
6
7
8
9
10
11
12 | #ocean
{
margin: auto;
margin-bottom: 10px;
width: 640px;
height: 400px;
border: 2px solid #000;
background-image: url('background.jpg');
background-position: center;
transition-property: background-position;
transition-duration: 10s;
}
|
Nous avançons bien !
Attaquons-nous maintenant au tableau de bord. Il contiendra les flèches de contrôle, à raison de trois par ligne : chaque flèche étant large et haute de 45 pixels, le tableau de bord doit avoir pour dimensions 135 pixels de haut et de large. Je préfère également mettre sa
position en «
relative » afin de placer au pixel près les flèches qu'il contiendra.
Code : CSS | #controls
{
width: 135px;
height: 135px;
margin: auto;
position: relative;
}
|
Les flèches ont toutes les mêmes dimensions et la même image de fond, ce n'est donc pas trop compliqué

:
Code : CSS | #controls div
{
width: 45px;
height: 45px;
position: absolute;
background-image: url('fleches.png');
background-repeat: no-repeat;
}
|
Pour les flèches, j'ai fait le choix d'employer la technique des
sprites CSS : cela ne permet d'avoir qu'une seule image à gérer pour toutes les flèches au lieu d'une vingtaine.
En contrepartie, le code CSS est bien plus pénible à écrire, mais il n'est pas plus complexe pour autant.
Code : CSS 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #fleche_hg{left: 0px; top: 0px; background-position: 0px top;}
#fleche_hg:hover{background-position: 0px bottom;}
#fleche_h{left: 45px; top: 0px; background-position: -45px top;}
#fleche_h:hover{background-position: -45px bottom;}
#fleche_hd{left: 90px; top: 0px; background-position: -90px top;}
#fleche_hd:hover{background-position: -90px bottom;}
#fleche_g{left: 0px; top: 45px; background-position: -135px top;}
#fleche_g:hover{background-position: -135px bottom;}
#fleche_d{left: 90px; top: 45px; background-position: -180px top;}
#fleche_d:hover{background-position: -180px bottom;}
#fleche_bg{left: 0px; top: 90px; background-position: -225px top;}
#fleche_bg:hover{background-position: -225px bottom;}
#fleche_b{left: 45px; top: 90px; background-position: -270px top;}
#fleche_b:hover{background-position: -270px bottom;}
#fleche_bd{left: 90px; top: 90px; background-position: -315px top;}
#fleche_bd:hover{background-position: -315px bottom;}
|
Tout est fin prêt ! Notre code CSS est en effet achevé, notre navigateur sait, grâce aux transitions, qu'il devra animer le changement de position de l'arrière-plan de l'océan… Il ne nous reste plus qu'à utiliser JavaScript pour ce faire.
La finalisation avec JavaScript
Nous pouvons désormais fermer notre fichier CSS pour revenir à notre fichier HTML et écrire le code JavaScript.
Nous avons déjà préparé notre fichier de façon à ce qu'il accueille le JavaScript correctement : je vous rappelle quand même que tout se passe dans la fonction
window.onload afin que le code ne s'exécute qu'une fois la page complètement chargée.
Bref, que voulons-nous faire exactement ?
Au passage de la souris sur une flèche, nous souhaitons modifier la propriété
background-position de l'océan.
Nous devrons donc écrire la fonction
onmouseover pour chaque flèche.
Pour déplacer le fond vers le coin supérieur gauche, il suffit de spécifier la propriété CSS
background-position à «
left top », pour le mettre en bas à droite à «
right bottom », etc.
Notre code peut donc être le suivant :
Code : JavaScript 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | //On stocke notre océan pour plus de clarté.
var ocean=document.getElementById('ocean');
document.getElementById('fleche_hg').onmouseover=function()
{
ocean.style.backgroundPosition='left top';
};
document.getElementById('fleche_h').onmouseover=function()
{
ocean.style.backgroundPosition='center top';
};
document.getElementById('fleche_hd').onmouseover=function()
{
ocean.style.backgroundPosition='right top';
};
document.getElementById('fleche_g').onmouseover=function()
{
ocean.style.backgroundPosition='left center';
};
document.getElementById('fleche_d').onmouseover=function()
{
ocean.style.backgroundPosition='right center';
};
document.getElementById('fleche_bg').onmouseover=function()
{
ocean.style.backgroundPosition='left bottom';
};
document.getElementById('fleche_b').onmouseover=function()
{
ocean.style.backgroundPosition='center bottom';
};
document.getElementById('fleche_bd').onmouseover=function()
{
ocean.style.backgroundPosition='right bottom';
};
|
Oui, ça fait long comme code, mais avouez qu'on a connu plus difficile en JavaScript.
Il serait également bon de recentrer l'arrière-plan lorsque nous ne sommes plus sur une flèche. Pour cela, il faut définir la méthode
onmouseout de chaque flèche. Cette fois, cette méthode doit faire la même chose quelle que soit la flèche, une boucle pourra donc nous tirer d'affaire.
Code : JavaScript 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | //On récupère tous les éléments enfants du tableau de bord.
var fleches=document.getElementById('controls').childNodes;
//Pour chaque enfant de notre tableau de bord...
for(var i in fleches)
{
/* Malheureusement, « fleches » ne contient pas que nos flèches,
il contient aussi des éléments « Text » : il nous faut donc vérifier que
l'enfant parcouru possède l'attribut « style ». Si oui, il s'agit d'une
de nos flèches, on peut donc continuer. */
if(fleches[i].style)
{
//On peut donc définir notre fonction.
fleches[i].onmouseout=function()
{
//Fonction qui recentre l'arrière-plan de l'océan.
ocean.style.backgroundPosition='center';
}
}
}
|
Malheureusement, cet exemple ne fonctionne pas toujours avec le navigateur Opera et pour une raison bien étrange : ce dernier ne prend pas encore correctement en charge les transitions de la propriété background-position... Gageons que cette erreur soit corrigée lors de la prochaine mise à jour du navigateur ! En attendant, il est toujours possible de ruser en changeant la façon de penser le système : on peut par exemple ajouter une balise <div> contenant notre fond, la placer en position « absolue » et la déplacer en jouant avec ses propriétés top et left.
Notre JavaScript modifie donc la position de l'arrière-plan selon les flèches survolées. Grâce à notre code CSS, le changement se fera progressivement, donnant ainsi l'illusion de mouvement ! Notez bien qu'aucune transition ne se fait dans le code JavaScript, tout se déroule dans le code CSS.
N'est-ce pas merveilleux ?
Allons plus loin avec transitionend
Détectons la fin de notre transition
Vous n'êtes pas sans savoir que JavaScript permet de lancer des fonctions lors de l'exécution d'événements. Ainsi, dans notre expérience sous-marine, nous bougions l'arrière-plan lors de l'événement « passage de la souris sur les flèches du tableau de bord ».
Les transitions CSS ont fait naître un nouvel événement :
transitionend. Comme les anglophones parmi vous l'auront deviné, cet événement se produit lorsque la transition s'est achevée.
Sur le papier, ça peut sembler pratique, notamment pour créer un système d'animations enchaînées. Malheureusement, tout comme la propriété CSS, l'événement JavaScript change de nom selon le navigateur du visiteur...
Ainsi, si Firefox utilise bien
transitionend, Opera préfère
OTransitionEnd tandis que Google Chrome a opté pour
webkitTransitionEnd. Bien entendu, Internet Explorer s'en contre-fiche, vu qu'il ne se préoccupe déjà pas des transitions en CSS.
Ce dernier point est un véritable problème. Si le navigateur de votre visiteur n'interprète pas les transitions CSS, l'événement transitionend ne se déclenchera jamais ! Évitez donc d'y utiliser des fonctions indispensables à la bonne navigation de votre site.
Tout ceci ne simplifie pas nos affaires et je vous propose donc un petit exemple pour comprendre le fonctionnement.
Code : HTML 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | <!DOCTYPE html>
<html>
<head>
<title>Découvrons transitionend</title>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script>
window.onload=function()
{
// Nombre de fois que l'animation a été achevée
var total=0;
// On stocke les noms des événements selon les navigateurs
var navigatorsProperties=['transitionend','OTransitionEnd','webkitTransitionEnd'];
// On parcourt chacun de ces événements
for(var i in navigatorsProperties)
{
// Et on les lie à notre élément HTML
document.getElementById('boite').addEventListener(navigatorsProperties[i],function()
{
total++;
document.getElementById('infos').innerHTML='Transition terminée '+total+' fois !';
},false);
}
};
</script>
</head>
<body>
<h1 id="infos">Passez la souris sur le carré !</h1>
<div id="boite"></div>
</body>
</html>
|
Bon, je ne vous montre pas le code CSS, j'y modifie juste la propriété
margin-left de ma
<div> au passage de la souris, et ce avec une
transition-duration de 2 secondes. Vous devriez être capables de le faire tout seul, maintenant.
Si vous avez testé le code, vous avez vu que l'événement
transitionend ne se déclenche que lorsque la transition a atteint son
état initial ou son
état final. Ainsi, si vous sortez la souris du carré pendant son déplacement, celui-ci revient vers son point de départ : la transition vers son état final est certes terminée mais aucun événement ne s'est déclenché ! En effet, le carré fait demi-tour vers son état initial, il considère donc que sa transition n'est pas achevée !
Quelle propriété a été animée ? Combien de temps a duré la transition ?
JavaScript nous offre la possibilité de connaître la propriété CSS qui a été animée. Pour cela, il suffit de récupérer le paramètre fourni par l'événement
transitionend. Ce paramètre contient en effet deux propriétés qui peuvent nous être utiles :
- propertyName contient le nom de la propriété CSS qui vient d'être animée ;
- elapsedTime indique le temps écoulé depuis le début de la transition, en secondes.
Code : JavaScript 1
2
3
4
5
6
7
8
9
10
11
12 | window.onload=function()
{
var navigatorsProperties=['transitionend','OTransitionEnd','webkitTransitionEnd'];
for(var i in navigatorsProperties)
{
document.getElementById('boite').addEventListener(navigatorsProperties[i],function(e)
{
document.getElementById('infos').innerHTML='Transition de la propriété <em>'+e.propertyName+'</em> terminée en <b>'+e.elapsedTime+'s</b> !';
},false);
}
};
|
Il y a toutefois une particularité pour elapsedTime : si la transition se coupe en plein milieu, il est remis à zéro. Essayez avec l'exemple ci-dessus en sortant la souris du carré pendant son déplacement, vous verrez que le temps indiqué à la fin de l'animation est toujours inférieur à deux secondes contrairement à ce qui a été indiqué dans le CSS !
Maintenant que tout est clair sur l'événement
transitionend, je vous propose un petit exemple d'utilisation.
La balade de Carapuce
Pour cet exercice, je vous propose de déplacer une
<div> dans une autre. Rien de bien palpitant me direz-vous, mais cela peut donner des résultats intéressants, vous verrez.
Tout d'abord, voici la structure de notre page HTML :
Code : HTML 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | <!DOCTYPE html>
<html>
<head>
<title>Une div se promène.</title>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript">
window.onload=function()
{
// Plus tard =D
};
</script>
</head>
<body>
<div id="conteneur">
<div id="moveDiv"></div>
</div>
</body>
</html>
|
Et son CSS correspondant, que vous pouvez bien entendu améliorer (il est franchement très basique et très moche

).
Code : CSS 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | #conteneur
{
width: 155px;
height: 130px;
position: relative;
margin: auto;
background-color: #000;
}
#moveDiv
{
width: 23px;
height: 19px;
position: absolute;
top: 10px;
left: 10px;
background-color: #fff;
transition: left 4s linear, top 5s linear;
}
|
Comme vous le voyez, j'ai décidé d'animer les propriétés
left et
top : le déplacement de notre
<div> sera donc fluide.
Il ne nous reste plus qu'à lancer la transition en JavaScript pour qu'elle se fasse dès le chargement de la page, sans aucune action de la part du visiteur. Ensuite, via
transitionend, on demandera un autre déplacement de sorte que notre élément visite chacun des quatre coins de son parent.
Code : JavaScript 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 | window.onload=function()
{
// Les coordonnées de chaque coin du conteneur
var topLeft=[10,10];
var topRight=[122,10];
var bottomLeft=[10,101];
var bottomRight=[122,101];
// On crée un objet littéral pour stocker nos valeurs
var objet=
{
// Notre div à déplacer
'div': document.getElementById('moveDiv'),
// La position vers laquelle elle se dirige
'position': topRight,
// Et une fonction pour la faire bouger !
'move': function()
{
this.div.style.left=this.position[0]+'px';
this.div.style.top=this.position[1]+'px';
}
}
var navigatorsProperties=['transitionend','OTransitionEnd','webkitTransitionEnd'];
for(var i in navigatorsProperties)
{
objet.div.addEventListener(navigatorsProperties[i],function(e)
{
/*Lorsque la div a fini son déplacement, on lui
indique un autre point à atteindre*/
switch(objet.position)
{
case topRight:
objet.position=bottomRight;
break;
case bottomRight:
objet.position=bottomLeft;
break;
case bottomLeft:
objet.position=topLeft;
break;
case topLeft:
objet.position=topRight;
break;
}
// Et on lui demande de se rendre à ce point !
objet.move();
},false);
}
// On lance le déplacement de notre div !
objet.move();
};
|
Notre
<div> parcourt bien chacun des quatre points de son conteneur.

Bon, ce n'est pas très joli, mais en appliquant des images en arrière-plan, il est possible d'avoir des résultats bien plus sympathiques. Tenez, prenons ces images :
N'est-ce pas mieux ? Si vous n'êtes pas encore convaincu par les transitions CSS3, je ne peux plus rien pour vous !
Pour modifier l'orientation du Carapuce, il suffit de changer sa propriété background-position dans notre code JavaScript, au niveau du switch.
Merci à Nesquik69 pour m'avoir suggéré la rédaction de cette partie sur transitionend. 