Partage
  • Partager sur Facebook
  • Partager sur Twitter

Hover pour apparaitre sous-sous-menu

    16 janvier 2023 à 11:31:08

    Bonjour,

    J'ai essayé de reproduire un menu assez complet avec sous-menu et sous-sous-menu. Quand je survole le menu, un sous-menu apparait : là pas de problème. Quand je survole le sous-menu, un sous-sous-menu doit apparaitre :

    Mais cela pose un problème pour le sous-sous-menu : si ce dernier est plus long, alors cela dépasse le parent. Il faudrait agrandir le parent.

    Voici l'effet voulu :

    On voit que la div parent s'agrandit avec la div enfant.

    En analysant avec l'inspecteur de code, on voit qu'au survol, la hauteur du parent s'adapte en fonction de la hauteur de l'enfant avec ce code généré dans le html au survol : style="--sub-height: 306px;"

    Comment peut-on agrandir la div parent en fonction de la taille de la div enfant ?

    En CSS, je crois que c'est impossible à cause de position:absolute.

    Je mets un extrait du code (tout ce qui utile, sinon trop de code) ici :

    https://codepen.io/furyfatal/pen/VwBzGeN

    -
    Edité par Terry-Bogard 16 janvier 2023 à 12:25:17

    • Partager sur Facebook
    • Partager sur Twitter
      16 janvier 2023 à 17:49:04

      Bonjour Terry-Bogard,

      Tu pourrais englober ton sous-menu et ton sous-sous-menu dans une même div ?

      Comme ça cette div aura la hauteur de l'enfant le plus grand, et donc tu pourras mettre le background white sur cette div parente ce qui te permettra d'avoir le bon affichage.

      • Partager sur Facebook
      • Partager sur Twitter
        16 janvier 2023 à 18:23:45

        Justement à cause de la position:absolute, le parent n'aura pas la hauteur de l'enfant le plus grand.

        • Partager sur Facebook
        • Partager sur Twitter
          16 janvier 2023 à 18:40:09

          Ah oui effectivement ça ne va pas être si simple...

          En allant voir le site dont tu parles, je remarque que la hauteur de l'élément parent varie quand on change de sous-menu, j'imagine donc qu'il y a un script javascript qui va attribué au sous-menu la bonne hauteur selon la hauteur du sous-sous-menu actif.

          Donc à chaque hover sur un élément de ton sous-menu, tu affiches le bon sous-sous-menu, puis tu attribues la hauteur de ce sous-sous-menu au sous-menu.

          Ca fait beaucoup de menu tout ça ^^

          • Partager sur Facebook
          • Partager sur Twitter
            16 janvier 2023 à 22:30:06

            Oui, c'est assez complexe. La version mobile, j'ai réussi à reproduire à l'identique. Mais sur la version bureau, je bloque sur le sous-sous-menu.

            Pour trouver la hauteur du sous-sous-menu actif, j'ai testé :

            children[0].height

            Mais ça n'a pas l'air de marcher.

            J'ai testé ensuite avec :

            children.length 

            Là j'arrive à récupérer le nombre de liens. J'ai donc pensé à multiplier le nombre de liens par un nombre de pixels.

            Ce qui donne ceci :

                    const subUl = document.querySelectorAll(".sub-ul");
                    const subLi = document.querySelectorAll(".sub-li");
                    const subSubMenuUl = document.querySelectorAll(".sub-sub-menu > ul");
            
                    for (let i = 0; i < subLi.length; i++) {
                        subLi[i].addEventListener("mouseover", function () {
                            let l = subSubMenuUl[i].children.length;
                            console.log(l);
            
                            subLi[i].parentNode.style.height = (38 * l) + "px";
                        });
            
                        subLi[i].addEventListener("mouseout", function () {
                            subLi[i].parentNode.style.height = "auto";
                        });
                    }

            Voici le résultat :

            https://codepen.io/furyfatal/pen/VwBzGeN

            Il y a 2 problèmes :

            - Ce n'est pas précis, car je n'ai pas la hauteur exacte.

            - Dès que je bouge la souris, le script appelle les fonctions en permanent. Ce n'est pas optimisé. Sur le site dont je m'inspire, c'est appelé une seule fois.

            • Partager sur Facebook
            • Partager sur Twitter
              18 janvier 2023 à 16:02:14

              Oh pas mal du tout le script que tu as fais même si ça rend effectivement pas au px près ça marche et c'est déjà ça !

              Pour résoudre le problème de hauteur je te propose ce code là dans le mouseover :

              const subSubMenu = subLi[i].querySelector(".sub-sub-menu");
              const subSubMenuHeight = subSubMenu.offsetHeight;
              subLi[i].parentNode.style.height = `${subSubMenuHeight}px`;


              Pour ce qui est de l'optimisation, cette fonction réalise juste une récupération de hauteur et un assignement, c'est vraiment très peu de complexité pour un processeur je ne me ferai pas de soucis par rapport à ça.

              Pour la troisième ligne si tu n'as pas encore vu ça, ça s'appelle Template literals et ça permet de mettre des variables dans une chaine de caractère.

              -
              Edité par NicolasMarafetti 18 janvier 2023 à 16:05:24

              • Partager sur Facebook
              • Partager sur Twitter
                20 janvier 2023 à 21:39:10

                Merci pour le offsetHeight.

                J'ai utilisé le window.matchMedia().matches pour que ce script s'exécute uniquement pour la version bureau, car la version mobile ne doit pas l'exécuter.

                Je rencontre tout de même un problème dans ce cas de figure : Durant le chargement de la page, je suis sur la version bureau. Après le chargement, je réduis la fenêtre (ce qui fait passer à la version mobile). Dans ce cas de figure, le script continue de s'exécuter même pour la version mobile, ce qui ne faut pas.

                const minx = window.matchMedia("(min-width: 981px)"); // Uniquement version bureau
                
                function functionMediaQuerie(minx) {
                    if (minx.matches) { // Si Media Querie correspond
                
                        console.log("Media Querie correspond");
                
                        const subLi = document.querySelectorAll(".sub-li");
                
                        for (let i = 0; i < subLi.length; i++) {
                            subLi[i].addEventListener("mouseover", function () {
                
                                const subSubMenu = subLi[i].querySelector(".sub-sub-menu");
                
                                if (subSubMenu) { // On vérifie qu'il y a le sous-sous-menu, car certains sous-menu n'ont pas de sous-sous-menu
                                    console.log(subSubMenu.offsetHeight);
                                    subLi[i].parentNode.style.height = (subSubMenu.offsetHeight + 2) + "px";
                                }
                            });
                
                            subLi[i].addEventListener("mouseout", function () {
                                subLi[i].parentNode.style.height = "auto";
                            });
                        }
                
                    }
                    else { // Si Media Querie ne correspond pas
                
                        console.log("Media Querie ne correspond pas");
                        // Normalement rien ne s'éxécute
                    }
                }
                
                functionMediaQuerie(minx); // Appel à la fonction au chargement
                minx.addEventListener("change", functionMediaQuerie); // Ecouteur d'événement sur changement d'état
                

                Je ne comprend pas pourquoi le script continue de s'exécuter si je passe en version mobile en réduisant la taille de fenetre.

                Test ici :

                https://codepen.io/furyfatal/pen/VwBzGeN

                -
                Edité par Terry-Bogard 20 janvier 2023 à 21:42:14

                • Partager sur Facebook
                • Partager sur Twitter
                  21 janvier 2023 à 7:39:48

                  Bonjour,

                  de ce que j'en comprends, le script ne s'exécute pas mais par contre il reste ses conséquences : tu as déclaré des EventListeners, donc… ils continuent d'écouter, sauf demande contraire. Pour moi il faut refaire une boucle sur les éléments de subLi et enlever les EventListener.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Pas d'aide concernant le code par MP, le forum est là pour ça :)

                    22 janvier 2023 à 16:40:17

                    Oui, c'est ce que je pense aussi : il reste des conséquences des eventListerners.

                    Mais je n'arrive pas à faire "removeEventListener" sur une fonction anonyme. Ca ne marche pas :

                    if (minx.matches) { // Si Media Querie correspond, on met les addEventListener
                    
                        console.log("Media Querie correspond");
                    
                        for (let i = 0; i < subLi.length; i++) {
                            subLi[i].addEventListener("mouseover", function () {
                    
                                const subSubMenu = subLi[i].querySelector(".sub-sub-menu");
                    
                                if (subSubMenu) { // On vérifie qu'il y a le sous-sous-menu, car certains sous-menu n'ont pas de sous-sous-menu
                                    console.log(subSubMenu.offsetHeight);
                                    subLi[i].parentNode.style.height = (subSubMenu.offsetHeight + 2) + "px";
                                }
                            });
                    
                            subLi[i].addEventListener("mouseout", function () {
                                subLi[i].parentNode.style.height = "auto";
                            });
                        }
                    
                    }
                    else { // Si Media Querie ne correspond pas, on met les removeEventListener
                    
                        console.log("Media Querie ne correspond pas");
                    
                        for (let i = 0; i < subLi.length; i++) {
                            subLi[i].removeEventListener("mouseover", function () {
                                // Ne rien faire
                            });
                    
                            subLi[i].removeEventListener("mouseout", function () {
                                // Ne rien faire
                            });
                        }
                    
                    }



                    -
                    Edité par Terry-Bogard 22 janvier 2023 à 16:41:24

                    • Partager sur Facebook
                    • Partager sur Twitter
                      22 janvier 2023 à 19:34:39

                      Ah oui, j'avais oublié ça. Eh bien, n'utilise pas de fonctions anonymes :) Déclare tes deux fonctions, avec un nom, et appelle-les (il est fort probable que le mot-clé this puisse remplacer subLi[i], puisque c'est sur ça que s'applique le listener.
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Pas d'aide concernant le code par MP, le forum est là pour ça :)

                        22 janvier 2023 à 21:12:53

                        J'avais pensé à déclarer 2 fonctions. Je voulais une confirmation que removeEventListener() ne marche pas sur une fonction anonyme.

                        Merci.

                        -
                        Edité par Terry-Bogard 22 janvier 2023 à 21:13:17

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Hover pour apparaitre sous-sous-menu

                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                        • Editeur
                        • Markdown