Select Page

Divi Mega Menus

< All Topics
Table of Contents

Plugin

https://divilife.com/downloads/divi-mega-pro/

Making a menu mega

On the WordPress Menus editor…

  • Click Screen Options at the top and make sure CSS Classes is checked.
  • Add a Custom Link to the top of the menu. Set the URL to # and the Link Text to Menu.
  • Set the CSS Class to mega-menu
  • Reorganize the existing menu hierarchy as a sub-menu under the new Menu Custom Link.


Changing the number of columns

By default, the mega menu will have 4 columns. If you have more than 4 top-level headers/links, the 5th will wrap around to the next row below the first 4.

With CSS, we can set as many columns as we want, in theory. 3 to 6 recommended. Choose a snippet below and copy it into the stylesheet.

3 columns
/* Turn off existing rules and set up 3-columns */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(3n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(3n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: 33.3%;
    margin: 0;
}
4 columns

Default! No styling needed.

5 columns
/* Turn off existing rules and set up 5-columns */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(5n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(5n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: 20%;
    margin: 0;
}
6 columns
/* Turn off existing rules and set up 6-columns */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(6n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(6n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: 16.66%;
    margin: 0;
}
7 columns
/* Turn off existing rules and set up 7-columns */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(7n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(7n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: 14.28%;
    margin: 0;
}
8 columns
/* Turn off existing rules and set up 8-columns */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(8n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(8n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: 12.5%;
    margin: 0;
}

Any number of columns

First, we need to overwrite the existing rules governing the columns. Paste this code in the child theme’s stylesheet:

/* Turn off existing rules */
}#top-menu li.mega-menu>ul>li:nth-of-type(4n) {
    clear: none;
}
#top-menu li.mega-menu>ul>li:nth-of-type(4n+1) {
    clear: none;
}

For a different number of columns, copy and edit the following snippet. Replace the first and second #s with the number of columns you want. Replace the third # with a percentage value equaling 100 divided by the number of columns. For example, 20 for 5 columns, 16.66 for 6 columns, and so on.

/* Set new rules */
#top-menu li.mega-menu>ul>li:nth-of-type(#n+1) {
    clear: left !important;
}
#top-menu li.mega-menu>ul>li:nth-of-type(#n) {
    clear: right !important;
}
#top-menu li.mega-menu > ul > li {
    width: #%;
    margin: 0;
}

Replace dropdown arrow with Hamburger icon

In the top-level Menu Custom Link, set the Navigation Label to:

<div class="hamburger">Menu</div>

(Replace Menu in the above with whatever arbitrary text you want, or remove it if you only want the hamburger icon.)

Now we’ll use CSS to add the actual hamburger logo. Add the following to the stylesheet:

/*** Hide hamburger menu item on mobile ***/
.et_mobile_menu .mega-menu >
 a{display:none;}
 
#top-menu .mega-menu > a, #et-secondary-nav .mega-menu > a {padding-bottom: 24px !important;}
 
/**** hide down arrow ****/
#top-menu .mega-menu > a:first-child:after, #et-secondary-nav .menu-item-has-children > a:first-child:after {display: none;}
 
/*** show hamburger icon ***/
.hamburger:after {
    font-family: "ETmodules" !important;
    font-weight: normal;
    font-style: normal;
    font-variant: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    line-height: 0.6em;
    text-transform: none;
    speak: none;
    position: relative;
    cursor: pointer;
    top: 0;
    left: 0;
    vertical-align: -11px;
    padding-right: 3px;
    font-size: 32px; /*change size of icon here*/
    content: "\61"; /*change icon here*/
    color: #333; /*change color of icon here*/
}

To change the color of the desktop-version hamburger, edit the last line in the snippet.

To change the color of the accompanying text:

.hamburger {color: #333;}

Delay menu closing on mouse-out

By default, dropdown menus including mega-menus will close instantly on mouse-out. This CSS markup will allow the menu to stay visible briefly, only disappearing if you mouse off the menu for a given amount of time.

Change the “.4s” and “.5s” values below to whatever timing you want.

@media (min-width: 981px) {
    .et-dropdown-removing > ul, .et-dropdown-removing .sub-menu {
        display: block !important;
    }
     .nav li ul {
        -webkit-transition: .4s ease-in-out .5s;
        transition: .4s ease-in-out .5s;
        visibility: hidden;
    }
    .nav li ul:hover {
        -webkit-transition: 0.4s ease-in-out 0s !important;
        transition: opacity 0.4s ease-in-out 0s !important;
        visibility: visible;
    }
    ul.sub-menu ul.sub-menu {
      display: block !important;
      visibility: inherit !important;
      transition: visibility 0s linear 0s !important;
    }
    ul.sub-menu li {
	 visibility: inherit;
	 transition: visibility 0s linear 0s !important;
	}
}

Make the mega menu scrollable

Divi menus aren’t natively scrollable on desktop, and a big mega menu can easily run offscreen. With this code, we can conditionally add a scroll bar when necessary.

Add the following to Theme Options>Integration>”Add code to the <head>…”:

<script type="text/javascript">
//This script provided by Ray Perea
//https://stackoverflow.com/questions/30912922/in-wordpress-using-elegant-themes-divi-theme-long-menus-dont-show

// Once the document is ready, execute this code
jQuery(document).ready(function(e) {
    'use strict';

    // Set the jQ var to jQuery.
    // You could also use $, but I use jQ... just my preference.
    var jQ = jQuery;

    // Execute the function that fixes the menus
    fixDiviMenus();

    // And whenever the window is resized, re-apply the fixes.
    jQ(window).resize(function() { fixDiviMenus(); });

});

// This variable simply holds a timeout integer.
// It is used so that we don't continually apply the fixes
// over and over as the window is being resized.
var ClFixTimeout;

// This function sets a timeout that fixes the menus
// We set a timeout so that we don't continually apply the fixes
// over and over as the window is being resized.
function fixDiviMenus() {
    "use strict";

    // If the timeout has already been created, clear it
    if (ClFixTimeout) { clearTimeout(ClFixTimeout); }

    // Wait half a second before applying the fixes
    ClFixTimeout = setTimeout(function() { applyDiviMenuFix(); }, 500);
}

// This function actually applies the fixes
function applyDiviMenuFix() {
    'use strict';

    var jQ = jQuery;

    // Get some variables that we use to determine
    // if our menus need fixing
    var windowElem = jQ(window);
    var windowHeight = windowElem.height();
    var windowWidth = windowElem.width();
    var scrollTop = windowElem.scrollTop();

    // If the screen is 980px or less,
    // then the mobile menu is shown. No reconfiguration necessary
    if (windowWidth < 981) { return; }

    // Get all the sub menus
    var subMenus = jQ('ul.sub-menu');

    // Reset the css properties on each sub menu
    // so that we can apply them again if need be.
    subMenus.each(function() {
        var menu = jQ(this);
        menu.css({
            'max-height': '',
            'overflow-y': '',
            'overflow-x': '',
            'margin-left': ''
        });
    });

    // Iterate each sub menu and apply fixes
    subMenus.each(function() {

        var menu = jQ(this);

        // Check to see if this is a mega menu.
        var isMegaMenu = menu.closest('.mega-menu').length > 0;

        // Only the direct sub menu should be considered.
        // All other children of mega menu do not need mods.
        if (isMegaMenu && (!menu.parent().hasClass('mega-menu'))) { return; }

        // Get some values that determine whether our menu
        // will go below the bottom of the screen
        var offset = menu.offset();
        var top = offset.top - scrollTop;
        var height = menu[0].offsetHeight;

        // Set the padding between the bottom of the menu 
        // and the bottom of the page
        // You can adjust this so that your menus go further
        // down or not
        var bottomPadding = 80;

        // Set the maximum height of the menu
        var maxHeight = windowHeight - top - bottomPadding;

        // If it's a mega menu or the menu stretches beyond
        // the bottom of the screen, set max height and overflow
        if (isMegaMenu || height > maxHeight) {
            menu.css({
                'max-height': maxHeight.toString() + 'px',
                'overflow-y': 'auto',
                'overflow-x': 'hidden'
            });
        }

        // If this is a mega menu, we don't need to check if it
        // goes off the right side of the screen
        if (isMegaMenu) { return; }

        // Check for a menu that goes off the right edge of the screen
        var left = offset.left;
        var width = menu[0].offsetWidth;
        var parentMenu = menu.parent().closest('ul');
        var maxLeft = windowWidth - width - 10;

        // If it goes off the edge
        if (left > maxLeft) {

            var marginLeft;

            // If this is a root drop down, simply shift
            // it to the left the correct number of pixels
            if (parentMenu.hasClass('nav')) {
                marginLeft = ( left - maxLeft ) * -1;
            }

            // Otherwise, this is a sub menu, we need to move
            // it to the other side of the parent menu
            else {
                marginLeft = width * 2 * -1;
            }

            // Apply the css to the menu
            menu.css({
                'margin-left': marginLeft.toString() + 'px'
            });

        }
    });
}
</script>

The scroll bar will look homely by default. I recommend styling it:

#top-menu li.mega-menu>ul.sub-menu::-webkit-scrollbar {
    width: 1em;
}
 
#top-menu li.mega-menu>ul.sub-menu::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
}
 
#top-menu li.mega-menu>ul.sub-menu::-webkit-scrollbar-thumb {
  background-color: darkgrey;
  outline: 1px solid slategrey;
}

Styling a mega menu

Obnoxiously, you now have two distinct menus to work on: the desktop version, and the mobile/responsive version.

You’ll likely want to add CSS classes to all your Menu items based on the hierarchy. For example:

  • Menu > mega-menu
    • Who We Are > mega-menu-1
      • Our Story > mega-menu-2
      • Our Details > mega-menu-2
    • What We Do > mega-menu-1
      • Services > mega-menu-2
        • Painting > mega-menu-3
        • Video > mega-menu-3
      • Portfolio > mega-menu-2


Changing the mobile hamburger color

.mobile_menu_bar:before {
  color: #ffffff !important;
}

Changing the background colors on both

.et_mobile_menu, #top-menu .mega-menu>.sub-menu {
  background-color: rgba(30,30,30,0.87) !important;
}

You’ll probably need to make sure the individual links don’t have their own backgrounds. Using the menu CSS class hierarchy outlined above:

.mega-menu-1, .mega-menu-2, .mega-menu-3 {
  background-color: rgba(0,0,0,0) !important;
}

Changing the menu top border line

The desktop version can be set through the Divi Customizer: Header & Navigation > Primary Menu Bar > Dropdown Menu Line Color.

The mobile version requires CSS:

.et_mobile_menu {
  border-color: #ffffff !important;
}

Formatting the links

This will style both versions of the menu. Use whatever classes you added to the Menu items. For example:

.mega-menu-1 > a {
  color: #0066ce!important;
 
}
.mega-menu-2 > a {
  font-weight: 600 !important;
  color: black !important;
  
}
.mega-menu-3 > a {
  font-weight: normal !important;
  text-indent: 10px;
  color: black !important;
}

Keep in mind that by default, the desktop/mobile menus are formatted differently. For example, the mobile menu automatically has full indentation, whereas desktop has none. To style the links in just one or the other…

Formatting the links in mobile only

Add a #mobile_menu and a space to the front of each rule. For example:

#mobile_menu .mega-menu-1 > a {
  color: #0066ce!important;
 
}
#mobile_menu .mega-menu-2 > a {
  font-weight: 600 !important;
  color: black !important;
  
}
#mobile_menu .mega-menu-3 > a {
  font-weight: normal !important;
  text-indent: 10px;
  color: black !important;
}

Formatting the links in desktop only

Add a #top-menu and a space to the front of each rule. For example:

#top-menu .mega-menu-1 > a {
  color: #0066ce!important;
 
}
#top-menu .mega-menu-2 > a {
  font-weight: 600 !important;
  color: black !important;
  
}
#top-menu .mega-menu-3 > a {
  font-weight: normal !important;
  text-indent: 10px;
  color: black !important;
}

Adding a banner or other stuff (advanced)

A few foundational notes before we start:

  • You can put whatever arbitrary HTML you want in the Navigation Label (with some jankiness.)
  • With CSS, you can disable menu items completely but still have them count as a column.
  • With CSS, you can resize any column or menu item as much as you want.

Let’s say we want to add a banner to a 4-column menu with the following major headings:

  • Menu
    • Products
    • Services
    • Team
    • Contact

First, we’ll add four Custom Links with custom CSS labels with # for the URL:

  • Navigation Label: Content, CSS Class: mega-menu-content
  • Navigation Label: dummy, CSS Class: mega-menu-dummy
  • Navigation Label: dummy, CSS Class: mega-menu-dummy
  • Navigation Label: dummy, CSS Class: mega-menu-dummy

Put these four links above your real headings, like so:

  • Menu
    • Content
    • dummy
    • dummy
    • dummy
    • Products
    • Services
    • Team
    • Contact

If you look at your menu now, you should see two rows in your mega menu: Content and the dummies across the top, and your real headings across the bottom.

The idea from here on out is to make the dummies invisible, extend Content into their territory, and add arbitrary HTML to it.

Disable dummies

Paste this into the stylesheet to disable the dummies:

.mega-menu-dummy>a {
  display: none !important;
}

Extend the Content box

Now comes the hard part: styling the Content box. Don’t worry about padding and margins yet. Add the following to your stylesheet:

.mega-menu-content {
  width: 100% !important;
  max-width: 100% !important;
  display:inline-block;
  background-color: rgba(0,102,206,0.5) !important;
}
.mega-menu-content>a:first-child {
  border-bottom: none !important;
  clear: right !important;
  width: 100% !important;
  max-width: 100% !important;
  pointer-events: none;
}

I’ll explain the a:first-child part in a bit.

Add arbitrary HTML

Write your HTML in Notepad or N++. Make liberal use of classes, because you never know what you’re going to want to style later. Bundle everything in a p, div, or span.

In the Divi Menus editor, open the Content link and paste your whole giant HTML block into the tiny Navigation Label field.

Now here’s the weird part. Let’s say my HTML was:

<span>
  <a href="hello.com">Hello</a>
</span>

When you save, head to the front-end, and Inspect, you’d expect to see this hierarchy:

<li class="mega-menu-content">
  <a href="#">
    <span>
      <a href="hello.com">Hello</a>
    </span>
  </a>
</li>

Instead, this is what you’ll get:

<li class="mega-menu-content">
  <a href="#">
    <span></span>
  </a>
  <a href="hello.com">Hello</a>
</li>

As you can see, any contents of the enclosing span get moved out as siblings of the initial anchor (which has whatever URL you entered for the Custom Link, in this case #). Same thing if you enclosed everything in a p or div. It’s super janky. That worthless anchor tag sitting out front is what I was targeting above with a:first-child.

Cleanup

From here on out, it’s just a matter of shuffling around padding and margins and tweaking the styling of whatever you put in the Content item.

For one thing, if you want the banner to take up the full width of the mega menu, you’ll need to remove the left, top, and right padding from the menus (and then probably add padding to the real columns, like mega-menu-1 in the snippet below).

/* the 5px is for the bottom, it can be anything. */
#top-menu li.mega-menu>ul.sub-menu, #mobile_menu {
  padding: 0px 0px 5px 0px !important;
}
#mobile_menu .sub-menu {
  padding: 0px 0px 0px 0px !important;
}
#top-menu li.mega-menu>ul>li.mega-menu-1 {
  padding-top: 25px !important;
  padding-left: 30px !important;
  padding-bottom: 15px !important;
}