:target
en CSSEn ajoutant un fragment à une URL, on peut accéder directement à un élément spécifique sur la page : celui dont l'identifiant correspond au fragment demandé.
Par exemple, le bloc suivant a pour identifiant toto
:
toto
!
Et le lien suivant pointe vers l'URL target.html#toto
,
c'est-à-dire vers l'élément toto
de cette page :
je suis un lien vers toto
.
Cliquer dessus pour voir le résultat.
On peut ainsi pointer vers un élément précis de n'importe quelle page web (à condition que cet élément ait un identifiant). Par exemple, ce lien pointe vers la section « Locomotion » de la page « Rorqual boréal » de Wikipédia.
Quand on veut pointer vers un élément sur la page courante, par exemple
toto
sur cette page, il suffit de mettre la partie « fragment »
dans l'URL : je pointe vers l'URL #toto
, je suis donc aussi un lien vers toto
.
:target
Normalement, quand on lui demande d'aller à une URL comportant un fragment, le navigateur essaie de placer l'élément visé tout en haut de la fenêtre. Cependant, ce n'est pas toujours possible si la page n'est pas assez longue (par exemple si elle fait moins d'un écran de hauteur) ou si la cible est proche du bas de la page.
Dans ce cas, la cible précise de l'URL peut ne pas être claire : la personne qui a cliqué sur le lien peut croire que le lien porte sur la page entière. Par exemple, il n'est pas clair si ce lien pointe vers « Annexes », « Articles connexes », « Références taxonomiques » ou « Liens externes ».
La pseudo-classe :target
vise à résoudre ce problème. Elle permet
de sélectionner l'élément visé par l'URL courante.
Par exemple,
le CSS
#titi:target { background-color: tomato; }va mettre l'élément d'identifiant
titi
en rouge si l'URL courante
du navigateur comporte le fragment #titi
.
Tester en cliquant sur ce lien vers titi
.
titi
!
Il est ainsi possible de mettre en évidence l'élément visé par un lien (typiquement un titre de section), ce qui permet d'éviter le problème expliqué plus haut.
Le cas d'utilisation de :target
peut paraître très spécifique, mais cette pseudo-classe est en
fait très puissante : en effet, il est possible d'appliquer n'importe
quel code CSS à l'élément visé, ce qui augmente énormément la flexibilité
de l'interface utilisateur sans nécessiter de JavaScript.
L'exemple typique de « détournement » de :target
est de l'utiliser pour faire une lightbox,
c'est-à-dire d'ouvrir une image en grand quand on clique dessus.
Pour commencer, on va simplement faire apparaître un élément lors d'un clic sur un lien. L'idée de base est très simple : on met l'élément à l'endroit où l'on veut qu'il apparaisse dans le HTML, et on fait un lien vers cet élément :
<div> <a href="#tutu">Cliquer ici pour faire apparaître tutu…</a> <p class="hidden" id="tutu"> Je suis <code>tutu</code>, l'élément caché ! </p> </div>Dans le CSS, on cache par défaut l'élément qu'on veut faire apparaître (de classe
hidden
)
mais on le fait apparaître s'il est cible de l'URL courante.
.hidden { display: none; } .hidden:target { display: block; background-color: gold; }
Quand on clique sur le lien, le fragment #tutu
s'ajoute à l'URL courante, l'élément tutu
est donc ciblé par l'URL courante, et comme il est
de classe hidden
, la deuxième règle CSS s'applique :
l'élément tutu
apparaît. Tester :
Je suis tutu
, l'élément caché !
Pour faire une lightbox, il suffit d'appliquer cette idée, avec quelques différences :
position:fixed
,
pour régler la position de l'image par rapport à la fenêtre du navigateur<div> <a href="#loup1" id="loup1-mini"> <img src="img/miniature.jpg" alt="Image d'un loup gris." /> </a> <a class="lightbox" href="#loup1-mini" id="loup1"> <img src="img/grande.jpg" alt="Image d'un loup gris." /> </a> </div>
.lightbox { display: none; } .lightbox:target { display: block; position: fixed; top: 10px; left: 10px; }
À part ces détails, le fonctionnement est exactement le même qu'auparavant. Cliquer sur l'image pour tester :
Le CSS ci-dessous ajoute un peu d'habillage à notre lightbox : on fait en sorte que le « lien retour » recouvre tout l'écran et on lui met un fond sombre (mais légèrement transparent). Le passage entre mode normal et mode lightbox est ainsi très clair ; de plus, on peut cliquer n'importe où sur la fenêtre pour revenir au mode normal.
Dans cet exemple, j'ai ajouté aussi des dimensions maximales pour l'image elle-même : quelle que soit la taille ou l'orientation de l'écran, l'image ne dépassera pas. Attention : il est donc impossible de zoomer sur l'image, ce qui n'est pas forcément idéal ! Une solution est présentée dans la section suivante.
.lightbox { display: none; } .lightbox:target { display: block; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, .8); } .lightbox img { display: block; margin: auto; max-height: 100%; max-width: 100%; }
Il est facile de centrer l'image horizontalement, mais c'est plus complexe de le faire
verticalement avec les outils classiques si la hauteur des images n'est pas toujours la même.
En particulier, on ne peut pas mettre l'élément de classe lightbox
en display:table-cell
,
car il est en position:fixed
. Il serait possible d'utiliser cette technique en ajoutant
un bloc intermédiaire entre la lightbox
et l'image. Une autre solution est d'utiliser flexbox (voir section suivante).
Dans cette version, pour garantir une ergonomie minimale, j'ai fait en sorte que l'image soit zoomable si jamais l'écran
est trop petit. Pour ce faire, j'ai mis la grande image dans un bloc de classe viewer
.
<div> <a href="#loup4" id="loup4-mini"> <img src="img/miniature.jpg" alt="Image d'un loup gris." /> </a> <a class="lightbox" href="#loup4-mini" id="loup4"> <div class="viewer"> <img src="img/grande.jpg" alt="Image d'un loup gris." /> </div> </a> </div>
Dans le CSS, les contraintes sur les dimensions maximales sont appliquées sur le viewer, qui est en overflow:auto
; aucune contrainte
n'est appliquée sur l'image elle-même. Ainsi, s'il y a suffisamment d'espace, il n'y aura aucune différence par rapport au cas précédent,
mais si l'écran est trop petit, l'internaute pourra se déplacer dans l'image.
Au passage, j'ai centré le viewer
verticalement en mettant tout simplement son conteneur en display:flex
et lui-même en margin:auto
.
.lightbox { display: none; } .lightbox:target { display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, .8); } .lightbox .viewer { margin: auto; max-height: 90%; max-width: 90%; overflow: auto; }
NB : le viewer
ne prend pas tout l'espace disponible pour limiter la confusion due à des ascenseurs multiples.
D'autre part, un bug de Firefox fait qu'il est impossible de scroller en déplaçant l'ascenseur à la souris (car l'ascenseur est dans
un lien). C'est ennuyeux, mais pas dramatique, car on peut toujours se déplacer (avec les flèches de l'ascenseur, ou à la molette), et de toute façon les appareils concernés
sont des téléphones et tablettes (interface tactile).