TypoScript Navigation mit Bootstrap 4 Mega Menu und Navbar
Wie man eine Navigation mit Hilfe von TypoScript und Bootstrap aufbaut, hatte ich in den letzten Artikeln dieses Wikis bereits beschrieben. Mit den Versionen 11 und 12 von TYPO3 gibt es die Möglichkeit, den MenuProcessor zu nutzen, um eine Navigation zu erstellen. Ein Vorteil des MenuProcessors in TypoScipt ist, dass man ein Array geliefert bekommt, auf das man Logiken aus Fluid anwenden kann. Daraus ergibt sich, dass man auch bei dieser Anforderung auf die VHS Extension verzichten kann, die zwar eine sehr große Hilfe ist, aber nicht immer bei einem TYPO3 Upgrade zur Verfügung steht. Mit dem MenuProcessor ist nun eine weitere Fähigkeit aus der VHS Extension in den TYPO3 Core übergegangen.
MenuProcessor für die Header Navigation
Um die Daten für die Navigation aus dem System auszulesen, kommt weiterhin TypoScript zum Einsatz. Hier ein Code Beispiel:
page { 10 { dataProcessing { ## Header Navigation 10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor 10 { levels = 3 as = headerMenu expandAll = 1 excludeUidList = 6, 74, 25 titleField = nav_title // title } } } }
Fluid Partial mit f:for Schleifen
Die einzelnen Variablen für das System können wir über TypoScript steuern:
- levels: Anzahl der darzustellenden Ebenen
- as: Name der Variable, die weiter verarbeitet werden soll
- expandAll: Sollen alle Untermenus ausgegeben werden?
- ExcludeUidList: UIDs von Seiten, die nicht in der Navigation erscheinen sollen
- titleField: Reihenfolge von Quellen für den ausgegebenen Titel der Seite
Die oben definierte Variable für das Array können wir nun an unser Fluid Template bzw. Partial übergeben und auswerten. Hier als Beispiel die MegaMenu Navigation der Agentur IBK:
<div class="container-fluid"> <div class="row navigation-top"> <div class="col-12 nav-container"> <nav class="navbar navbar-expand-md navbar-light bg-light"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbar"> <ul class="navbar-nav mr-auto"> [...hier der Code für die einzelnen Ebenen...] </ul> </div> </nav> </div> </div> </div>
Wir gehen hier in mehreren Schleifen durch die Variable HeaderMenu. Über das Objekt Children können wir per Condition abfragen, ob ein Menupunkt Unterpunkte hat. Diese können wir dann in einer weiteren Schleife durchgehen. Die Links zu den einzelnen Seiten können wir mit dem <f:link.page> Viewhelper erzeugen. Dies ist der Code für den Platzhalter des Code Snippets oben:
<f:for each="{headerMenu}" as="menuLevel1Item"> <li class="nav-item dropdown has-megamenu"> <!-- Erste Ebene der Navigation --> <a class="nav-link dropdown-toggle" title="{menuLevel1Item.data.subtitle}" href="#" id="dropdown{menuLevel1Item.data.uid}" data-bs-toggle="dropdown"> {menuLevel1Item.data.title} </a> <div class="dropdown-menu megamenu container-fluid" role="menu"> <div class="row"> <f:if condition="{menuLevel1Item.children}"> <f:for each="{menuLevel1Item.children}" as="menuLevel2Item"> <!-- Zweite Ebene der Navigation --> <div class="col-12 col-sm-6 col-md-4 col-lg-3 div-nav"> <div class="col-megamenu"> <f:link.page pageUid="{menuLevel2Item.data.uid}" title="{menuLevel2Item.data.seo_title}" class="link-level3 strong"> {menuLevel2Item.data.title} </f:link.page> <f:if condition="{menuLevel2Item.children}"> <f:for each="{menuLevel2Item.children}" as="menuLevel3Item"> <!-- Dritte Ebene der Navigation --> <div class="row"> <div class="col-12 nav-level3"> <f:link.page pageUid="{menuLevel3Item.data.uid}" class="link-level3" title="{menuLevel3Item.data.seo_title}"> {menuLevel3Item.data.title} </f:link.page> </div> </div> </f:for> </f:if> </div> </div> </f:for> </f:if> </div> </div> </li> </f:for>
Style Sheet für MegaMenu
Das CSS dazu findet sich hier:
.has-megamenu { position: static; } .megamenu, .dropdown-menu.megamenu { margin-top: 0px; } @media (max-width:767px) { .megamenu, .dropdown-menu.megamenu { width: calc(100% + 20px); margin-left: -10px; margin-right: -10px; } } .nav-container { padding: 0; } #navbar>ul>li.nav-item.dropdown.has-megamenu>div { border-radius: 0; background-color: #eee; border: 5px #729ebd solid; padding: 0; box-shadow: 0px 30px 30px -15px #333; } #navbar>ul>li.nav-item.dropdown.has-megamenu>div .row { margin: 0; } .div-nav { padding: 5px; color: #333; transition: all 0.5s; } .div-nav:hover { background-color: #729ebd; color: #111; transition: all 0.8s; } nav.navbar { background-color: #275ba4; border: none; margin-top: 0px; margin-bottom: 0; min-height: 40px; padding-left: 15px; padding-right: 15px; border-radius: 0 0 0 0; background: linear-gradient(#275ba4, #729ebd); } ul.nav.navbar-nav>li>a { color: #a4c2ed; padding: 12px 8px; } ul.nav.navbar-nav>li>a:hover { color: #ccc; background: linear-gradient(#275ba4, #a4c2ed); } ul.dropdown-menu { padding: 0; } #navbar.navbar-collapse.collapse>ul.nav.navbar-nav>li.dropdown>ul.dropdown-menu { background-color: #729ebd; } .dropdown-menu>.active>a:focus, .dropdown-menu>.active>a { background-color: #275ba4; } .dropdown-menu { border: none; }
#navbar.navbar-collapse.collapse>ul.nav.navbar-nav>li.active>a { background: linear-gradient(#275ba4, #729ebd); color: #ddd; } #navbar.navbar-collapse.collapse>ul.nav.navbar-nav>li.dropdown.open>a.dropdown-toggle { background-color: #729ebd; } .dropdown-menu>.active>a:hover { background-color: #a4c2ed; color: #275ba4; } .dropdown-menu>li>a:hover { color: #275ba4; background-color: #a4c2ed; } div#navbar.navbar-collapse.collapse>ul.nav.navbar-nav>li.dropdown.active>a.dropdown-toggle { color: #eee; } .nav-level3 { padding: 0px 1px 0px 1px; font-size: 14px; } .nav-level3-img { padding: 1px 1px 1px 1px; } a.link-level3 { color: #275ba4; font-size: 14px; line-height: 22px; transition: all ease 0.5s; } a.link-level3:hover { color: #e8eff9; transition: all ease 0.5s; text-decoration: none; }
JavaScript Code für MegaMenu
Schließlich brauchen wir noch den JavaScript Code, um das MegaMenu zum Leben zu erwecken
document.addEventListener("DOMContentLoaded", function(){ document.querySelectorAll('.dropdown-menu').forEach(function(element){ element.addEventListener('click', function (e) { e.stopPropagation(); }); }) });