27 juillet 2014

:target : pseudo-classe à concilier avec pushState(),
et IE 8

Edit du 31/07/2014 : voir aussi :target : pseudo-classe rafraîchie avec pushState().

La pseudo-classe CSS 3 ':target' sélectionne l'élément du DOM pouvant correspondre à une ancre dans l'url. Une navigation interne à la page, d'ancre en ancre, se fait en général directement, et l'un des soucis serait alors de savoir si l'on veut tenir compte d'Internet Explorer 8.

Et IE 8

Il y a une réponse avec 'onhashchange' : La pseudo-classe ':target‘ : alternative pour IE 8.

"pushState()" ne rafraîchit pas ':target'

Dès que l'on rajoute une couche de liaison entre navigation interne et l'url de la page, une question épineuse se pose. La manipulation de l'historique via les méthodes "pushState()" et "replaceState()" joue avec l'écriture de l'url (dans la barre d'url du navigateur aussi bien que dans l'historique de navigation) sans modifier l'état du document. A partir de là, s'il y a déjà au même instant un élément sélectionné via ':target', alors il ne subit aucun rafraîchissement. Il reste sélectionné, en contradiction avec la nouvelle apparence de l'url.

Il semblerait que ce soit un bogue - bien qu'en fait, ça semble cohérent avec le principe des deux méthodes - ne manipuler que l'historique :

  1. Bug 83490 – history pushState doesn't affect :target selector
  2. Issue 89165 - chromium - history pushState doesn't affect :target selector - An open-source project to help move the web forward. - Google Project Hosting

J'ignore si la question se pose sur Internet Explorer, qui supporte l'API "history" depuis sa version 10, mais elle est bien présente, et gênante, sur Firefox et webkit.
J'ai développé une manière de positionner certains éléments en position 'fixed' qui permet de concilier ':target' avec "pushState()"-"replaceState()" et/ou un scroll animé, tout en conservant une navigation cohérente.

Solution pour un retour en début de page

Pour un retour en début de page avec scroll animé et nettoyage d'url, il faut d'abord passer l'ancre du début de page dans l'url de façon classique. L'élément du haut de page étant en position 'fixed', il ne se passe rien, mais à l'ancienne url est associée le niveau de scroll actuel, qui sera ainsi restitué lors d'une navigation au clavier ou via les boutons "précédent"-"suivant" du navigateur.

Ensuite, "replaceState()", qui clarifie l'url sans créer de nouvelle entrée dans l'historique - pour la même raison, conserver un historique employable. Les deux instructions se suivant, seule la deuxième est manifeste.

Puis un scroll animé vers le haut.

Cet exemple détecte le support de ':target', celui-ci propose aussi de simuler l'absence de l'API "history".

Pour une navigation globale sur la page

C'est moins propre. Cela consiste à cloner la cible (avec jQuery), à passer la cible en position 'fixed', à introduire son clone après lui, à passer l'ancre de la cible dans l'url de façon classique, à extraire le clone du DOM, à soustraire le style 'fixed' de la cible, puis à lancer le scroll animé vers la cible.

C'est le respect de cet ordre des instructions qui permet, là aussi, de conserver un historique exploitable : contre-exemple 1 ; contre-exemple 2.

Là, l'API "history" n'est pas requise.

L'alternative pour IE 8 s'insère facilement dans ces développements.
Note : il apparaît que les boutons de déplacement dans l'historique fonctionnent sans rafraîchir ':target' sur IE, IE 8 excepté. A l'étude : redoubler sur IE ':target' par 'onhashchange' quand l'événement n'est pas consécutif à un clic ?

Code

Le focus est pris en compte avec l'attribut 'tabindex'.

Les pages d'equatorium.net (dont /ex--exemples/) sont aussi sur Github.

Quand l'on se veut Fighting the Jump! (On :target | CSS-Tricks), cela peut faire penser à La pseudo-classe ':target‘ : sans aucun scroll mais en plus accessible appliqué à des contenus retreints. Le code est presque comme "pour une navigation globale sur la page", sans le scroll.

La détection du support de ':target' provient de www.zachleat.com/test/css-target-feature-test/querySelector.html.

Aucun commentaire: