11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour, j'ai un problème en javascript et j'aurais besoins de votre aide.
J'ai souligné un lien en utilisant l'attribut ::after comme ceci :


li {
      font-size: $links_fs;
      margin: 0 20px;
      width: 145px;
      text-align: center;
      cursor: pointer;
      &:first-child::after {
        content: '';
        display: block;
        position: relative;
        background: #000;
        top: 5px;
        $width: 105%;
        width: $width;
        left: - ($width - 100% ) / 2;
        height: 2px;
      }
    }


J'ai besoins, pour faire une animation en javascript, de sélectionner cette barre mais impossible ...


console.log(document.querySelector('#nav-links li:first-child'));
console.log(document.querySelector('#nav-links li:first-child::after'));


Ceci me retourne dans la console :


<li>
    "ACCUEIL"
    ::after
</li>
null


Si j'ai fait une erreur ou que vous avez une solution, ça me ferait plaisir (:
Bonne soirée à tous !
La réponse courte : on ne peut pas. En effet, les pseudo éléments ne sont pas un nœud dans le doom, mais du style pur. Et en javascript on ne peut sélectionner que des éléments ou des noeuds.

Il faut trouver des solutions de contournement :
- créer une classe d'état pour l'élément cible et prévoir à l'avance un style pour les pseudo éléments liés à cette classe,
- idem que précédemment, mais avec des variables CSS.
Modifié par Olivier C (28 Oct 2020 - 20:57)
Olivier C a écrit :
La réponse courte : on ne peut pas. En effet, les pseudo éléments ne sont pas un nœud dans le doom, mais du style pur. Et en javascript on ne peut sélectionner que des éléments ou des noeuds.

Il faut trouver des solutions de contournement :
- créer une classe d'état pour l'élément cible et prévoir à l'avance un style pour les pseudo éléments liés à cette classe,
- idem que précédemment, mais avec des variables CSS.


Pour être honnête j'ai absolument rien comprit ... Tu aurais un vidéo, un site ou quelque chose de mieux détailler car ça m'interesse beaucoup !
Merci de ta réponse et bonne soirée
Modérateur
L'idée d'Olivier est assez simple en réalité. Plutôt que du vouloir cibler tes ::before/::after en JS, il te suffit d'ajouter un class (toto) au hover/click/… sur ton <li> (en JS). Ensuite dans ta CSS, tu auras :
li {
      …
      &:first-child::after {
        …
      }
      &.toto:first-child::after {
        // ici tu peux modifier tes propriétés
      }
}

Cela veut dire que tu vas garder les styles dans ta feuille de style (un endroit centralisé si tu veux modifier plus tard). Et si tu veux visuellement modifier ton état hover/click/… tu peux plus facilement réutiliser tes variables SCSS et autres Smiley smile
Ce que tu essayes de faire est extrêmement hacky.. et je te recommande fortement de créer des éléments réels au lieu d'essayer d'animer des pseudo-éléments. Cependant, pour infos: la seule façon d'animer un pseudo-élément est d'insérer une style balise et de changer la valeur dans le CSS , comme ...

var styles = document.getElementById("pseudo-mover")
var distance = 100;

var move = function(){
    styles.innerHTML = ".box:after {left: " + distance + "px}";
    distance++;
    if (distance < 200) 
        setTimeout(move, 30);    
}

move()
Meilleure solution
Modérateur
Et l'eau,

Pourquoi veux tu dynamiser un :before/:after ? ne peux tu pas le faire avec un @keyframe ? Que veux tu réaliser ?

@Jencal : +1 C'est ce dont je me sers si je n'ai pas le choix.
Modifié par niuxe (29 Oct 2020 - 12:13)
niuxe a écrit :
Et l'eau,

Pourquoi veux tu dynamiser un :before/:after ? ne peux tu pas le faire avec un @keyframe ? Que veux tu réaliser ?

@Jencal : +1 C'est ce dont je me sers si je n'ai pas le choix.


J'ai un menu avec 5 <li> côté à côté avec une width de 150px chacun, mon <li> a un élément ::after qui forme un border-bottom noir. Lorsque je survol un des 5 liens, le ::after du premier li se déplace sous cet élément avec une transition ( si c'est le troisième li, le ::after se déplace de + 150px * 3). J'espere avoir été clair (:
JENCAL a écrit :
Ce que tu essayes de faire est extrêmement hacky.. et je te recommande fortement de créer des éléments réels au lieu d'essayer d'animer des pseudo-éléments. Cependant, pour infos: la seule façon d'animer un pseudo-élément est d'insérer une style balise et de changer la valeur dans le CSS , comme ...

var styles = document.getElementById("pseudo-mover")
var distance = 100;

var move = function(){
    styles.innerHTML = ".box:after {left: " + distance + "px}";
    distance++;
    if (distance &lt; 200) 
        setTimeout(move, 30);    
}

move()


Merci beaucoup de ta réponse, j'ai ici comprit le fonctionnement mais c'est bien .box:after ou c'est une erreur de frappe ?? ( j'aurais pensé .box::after )
Sinon c'est une super solution, merci beaucoup.
Yordi a écrit :
L'idée d'Olivier est assez simple en réalité. Plutôt que du vouloir cibler tes ::before/::after en JS, il te suffit d'ajouter un class (toto) au hover/click/… sur ton &lt;li&gt; (en JS). Ensuite dans ta CSS, tu auras :
li {
      …
      &amp;:first-child::after {
        …
      }
      &amp;.toto:first-child::after {
        // ici tu peux modifier tes propriétés
      }
}

Cela veut dire que tu vas garder les styles dans ta feuille de style (un endroit centralisé si tu veux modifier plus tard). Et si tu veux visuellement modifier ton état hover/click/… tu peux plus facilement réutiliser tes variables SCSS et autres Smiley smile


C'est effectivement une solution mais j'aime moins le côté bidouillage ... (:
J'aurais dû préciser l'utilisation que j'allais faire du ciblage du ::after car je penses que ça s'avérerait un peu comprit en css à moins d'utiliser une boucle scss ce qui est je penses un peu hoverkill.
Merci beaucoup de ta réponse, excellente soirée !!