Click sur un pseudo-element

Comment déterminer en javascript qu'un événement click a eu lieu sur un pseudo-élément et pas ailleurs dans l'élément parent ?

Problématique

Les pseudo-éléments sont très utiles dans de nombreux cas, que ce soit en typographie ou en design. Le problème, c'est qu'ils ne font pas partis du DOM ; impossible donc d'agir sur eux en javascript. Comment dés lors surveiller des actions qui leur sont liées comme le click ? La problématique peut aussi s'étendre au fait que l'on souhaite parfois définir uniquement une zone particulière d'un élément sensible à l'interaction souris.

Première solution : BoundClick

Après une petite demi-heure de reflexion / codage, et une autre demi-heure de test / debug, je suis arrivé à quelque chose d'à peu près satisfaisant.

  • Le code reste très simple : il faudrait ajouter des tests de type pour les paramètres par exemple.
  • La technique n'est pas limitée à la gestion d'événements sur les pseudo-éléments ; elle peut aussi être utilisée pour cibler toute zone particulière d'un élément.
  • Elle n'est sans doute pas applicable tel quel dans tous les cas de figures ; je n'ai testé que ceux dont j'avais besoin.
  • Elle a été validée sous Firefox 17, Opera 12.10, Chrome 23 et Internet Explorer 9/10.
Contenu indisponible.
BoundClick.js

A noter que l'objet est déclaré ici en tant que module AMD ; le code peut évidemment être utilisé sans cela puisqu'il n'a aucune dépendance, si ce n'est un navigateur moderne.

Exemple d'utilisation

  • Cibler le pseudo-élément :before des items de liste à puces.
  • Changer la couleur du texte de l'item sur le click.
<ul id="demo-target">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
</ul>
Code HTML de l'exemple.
#demo-target > li {
    list-style: none;
}
#demo-target > li:before {
    content: "";
    display: inline-block;
    margin: 0 5px 0 0;
    width: 14px;
    height: 14px;
    line-height: 1;
    background: #00f;
}
Code CSS de l'exemple. Nous faisons du pseudo-élément :before des items de simples carrés bleus.
var bounder = new BoundClick(
    document.getElementById('demo-target'),
    { width: 14, height: 14 },
    function (e) { 
        if (!e.target.style.color) {
            e.target.style.color = '#f00';
        } else {
            e.target.style.color = '';
        }
    },
    function (e) { 
        return e.target.nodeName.toLowerCase() === 'li'; 
    }
);
Gérer le click limité sur la zone du pseudo-élément :before des items de la liste à puces.
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
Démonstration : la zone bleue est l'unique zone cliquable des items.

Autre technique : offsetX / offsetY

On peut obtenir quelque chose de comparable avec un code plus simple, qui n'aura évidemment pas toutes les fonctionnalités d'un objet comme le BoundClick mais qui peut répondre à des besoins courants. Il s'agit ici de se baser sur les propriétés offsetX et offsetY des événements souris. Si on reprend l'exemple ci-dessus, on pourrait écrire queqlue chose comme :

// Click listener
const onClick = function (e) {
    let li = e.target;
    if (li.nodeName.toLowerCase() === 'li' && e.offsetX < 14 && 
            e.offsetY < 14) {
        if (!li.style.color) {
            li.style.color = '#f00';
        } else {
            li.style.color = '';
        }
    }
};
// element
const element = document.getElementById('demo-target');
// listen
element.addEventListener('click', onClick);
Ecoute du click sur la liste.
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
Démonstration : la zone bleue est l'unique zone cliquable des items.

Ressources et références

Titre
CSS3 Generated and Replaced Content Module
Auteurs
Ian HICKSON
Editeur
W3C
Date
Chapitre
4. Pseudo-elements
Titre
element.getBoundingClientRect
Editeur
Mozilla Developer Network
Date
Titre
MouseEvent.offsetX
Editeur
Mozilla Developer Network
Date
Titre
MouseEvent.offsetY
Editeur
Mozilla Developer Network
Date

Historique

2013-01-02
  • add création de l'article.
2017-06-08