: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> <p class="hidden" id="tutu"> Je suis <code>tutu</code>, l'élément caché ! </p> <a href="#tutu">Cliquer ici pour faire apparaître tutu…</a> </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%; }
À noter que le margin:auto
sur l'image centre l'image horizontalement, mais pas verticalement :
en CSS « classique » auto
vaut toujours 0
pour les marges verticales. Il y a ainsi plusieurs aspects pour lesquels CSS ne traite
pas de la même façon les dimensions horizontales et verticales, pour des raisons a priori principalement « historiques ». Voir la section suivante pour une solution moderne.
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.
NB : le viewer
ne prend pas tout l'espace disponible pour limiter la confusion due à des ascenseurs multiples.
Au passage, j'ai centré le viewer
verticalement en mettant tout simplement son conteneur en display:grid
et lui-même en margin:auto
. En effet, pour un item de grille, margin:auto
fonctionne comme on le souhaite dans les deux dimensions :
les personnes qui ont conçu les spécs ont profité de ce contexte « moderne » pour modifier le comportement de margin: auto
sans casser tous les sites web existants.
Ça marche d'ailleurs aussi avec le conteneur en display:flex
, pour les mêmes raisons.
.lightbox { display: none; } .lightbox:target { display: grid; 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; }