Divi - Menu mobile con sottomenu a cascata

Il modulo menu che viene reso disponibile da Divi è molto potente, ma purtroppo è carente in una funzionalità abbastanza importante: da mobile non si possono avere sottomenu da poter chiudere ed aprire. Di default, tutti gli elementi del menu e dei sottomenu sono immediatamente visibili, con quest’ultimi indentati a destra per rendere chiaro che fanno parte di un sottomenu.

Questo è l’aspetto del menu di default di Divi:

Menu mobile come visualizzato di default da Divi

L’obiettivo che vogliamo raggiungere, invece è questo:

Menu mobile con dropdown per i sottomenu

Come possiamo vedere, in questa foto gli elementi del sottomenu sono nascosti e possono essere mostrati solo premendo sull’icona alla destra di “Servizi”.

Anche gli sviluppatori di Divi si sono resi conto che avere dei menu che si possono chiudere e aprire da mobile è una funzionalità che molti desiderano, infatti hanno rilasciato questo post nel loro blog che mostra del codice da poter usare per creare questa funzionalità. Ma se c’è già una risposta ufficiale a questo bisogno, perché scrivere un’altro articolo al riguardo?

Perché la soluzione presentata non mi piace. La trovo poco pratica e limitante, principalmente per due motivi:

  • per ogni elemento che ha un sottomenu bisogna aggiungere una classe specifica (a mano, nel backend di wordpress);
  • per ogni elemento dei sottomenu bisogna aggiungere una classe (sempre a mano);
  • se un elemento ha dei sottomenu, ma è anch’esso un link, quell’elemento perderà la sua funzionalità di link e potrà essere usato solo per aprire il sottomenu.

Quindi, ho deciso di scrivere un codice personale da usare in queste circostanze.

Il codice

Prima di tutto, includiamo nella nostra pagina il codice javascript che segue:

function getSubmenusContainer(menu) {
    return [...menu.querySelectorAll("li.menu-item-has-children")];
}

function toggleDropdown(e) {
    e.preventDefault();
    e.stopPropagation();
    let submenuContainer = this.parentElement;
    submenuContainer.classList.toggle('sub-menu-open');
}

function addSubmenuDropdown(submenu) {
    let dropdown = document.createElement("span");
    dropdown.classList.add("sub-menu-dropdown");
    dropdown.textContent = "3"; // Down arrow when using font 'ET Modules'
    dropdown.addEventListener('click', toggleDropdown);

    submenu.appendChild(dropdown); // First child of submenu is the text link
}

function enableSubmenu(menu) {
    
    let mobile_menu = menu.querySelector(".et_mobile_menu");
    mobile_menu.classList.add("has-mobile-dropdown");

    let submenuContainers = getSubmenusContainer(menu);
    for (let submenu of submenuContainers) {
        addSubmenuDropdown(submenu);
    }
}

Come vedete, il codice è molto breve. La funzione che più ci interessa si chiama enableSubmenu(). Passando l’elemento radice del menu a questa funzione, attiveremo la funzionalità dei menu a cascata sul telefono.

Questo codice non fa altro che aggiungere un tastino dove sono presenti dei sottomenu e attivare una classe CSS quando questo tasto viene premuto. Inoltre, aggiunge una classe che ci permette di identificare i menu che hanno questa funzionalità attiva.

Il codice CSS è quello che fa buona parte del lavoro, nascondendo gli elementi dei sottomenu e posizionando il tasto nel modo giusto:

/* Necessario per il posizionamento del pulsante */
.et_mobile_menu.has-mobile-dropdown .menu-item-has-children {
    position: relative;
}

/* Stili del pulsante */
.sub-menu-dropdown {
    position: absolute;
    top: 0;
    right: 0;
    font-family: 'ETMODULES';
    height: 40px;
    width: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: transform .3s;
}

.et_mobile_menu.has-mobile-dropdown .sub-menu-open > .sub-menu-dropdown {
    transform: rotate(-180deg);
}

/* Nasconde gli elementi quando il sottomenu è chiuso */
.et_mobile_menu.has-mobile-dropdown .menu-item-has-children > .sub-menu > li {
    display: none !important; 
}

.et_mobile_menu.has-mobile-dropdown .menu-item-has-children.sub-menu-open > .sub-menu > li {
    display: block !important;
}

Una volta inseriti nella pagina questi due codici, possiamo utilizzare enableSubmenu() per decidere su quale menu attivare questa funzione. Per esempio, se diamo al menu un id “main-menu”, possiamo attivare la funzionalità in questo modo:

let menu = document.querySelector("main-menu");
enableSubmenu(menu);

Ed il gioco è fatto!

Qualcosa in più

Probabilmente in futuro creerò un plugin per estendere Divi con tutte queste piccole personalizzazioni da poter utilizzare nei miei progetti, e lo renderò disponibile anche ad altri.

Vi farò sapere se questo progetto andrà in porto, nel frattempo vi auguro buon lavoro!