adding new navigation
Description of the Change
See #45 I have remade the navigation based on issues found and features I felt were missing.
Major Changes
- The breakpoint param is a bit different.
- The menu now adds a class to submenus if they will appear offscreen. this uses a resize event.
- submenu selector can be changed
- menu toggle is optional
- some aria attributes are added for you with defaults if you forgot to add them.
- css changes with less overhead needed to get menus looking right
- hover events for applicable devices
- parameters now available for callbacks
How to use
Similar to the original you would create a navigation instance, only this time you have more options.
Second parameter breakpoint changes: The second parameter doesn't need to take a media query. It can now take a media query or a css unit or a boolean (20px, 60em, --var, true, false). Below this unit means mobile, above it means desktop. This controls when the menu is vertical or horizontal. When vertical, hover events will be ignored. CSS is also applied a bit differently for vertical menus. It can also be set to true/false which means the menu will be considered vertical or horizontal at all times. True means mobile, which means always vertical. This comes in handy, for example, on a menu placed in a sidebar.
A menu toggle button is now optional. you can pass navButtonElement of false for no button.
Options
- navButtonElement: selector for a menu toggle, if using one. It will need an aria-controls set to any element you want to open/close
- subMenuElement: sub menu selector, defaults to '.sub-menu',
- activeClass: class added to li menu item when submenu is considered "opened". defaults to "active"
- desktopHover: allow hover events on top level menu items for hover-capable devices
- autoCloseMenu: close mobile menu when clicking elsewhere. if string given it wont close unless that selector or children are clicked.
- onInit: function after menu is instantiated
- onMenuOpen: function for when menu is opened. param passed is the menu button that opened it
- onMenuClose: function for when menu is closed. param passed is the menu button that closed it
- onSubMenuOpen: function for after a submenu opened. Params passed are the submenu and the menu item that holds the submenu
- onSubMenuClose: function for after a submenu closed. Params passed are the submenu and the menu item that holds the submenu
- onResize: function runs when menu is resized. Also runs once on instantiation.
Helpful Properties
You can use some class properties to help you when creating some callbacks.
- isMobile: returns true/false based on the breakpoint you gave.
- isMenuHorizontal: for more precision in rare cases, this can let you know if the menu is currently flexed with a direction of row.
Example
let nav = new CreateNavigation('#primary-nav', {
breakpoint: '--nav-breakpoint',
navButtonElement: '.menu-toggle',
onSubMenuOpen: (menuItem, submenu)=>{
if(nav.isMobile()){
$(submenu).slideDown();
}
},
onSubMenuClose: (menuItem, submenu)=>{
if(nav.isMobile()){
$(submenu).slideUp();
}
}
})
The Above example will make a menu that slides the submenus up and down on mobile when the menu is vertical. We will assume a css variable of --nav-breakpoint exists. If this variable changes at any time, the js will update. Below is html markup that matches the above js.
Html/PHP Markup Example
<button class="menu-toggle" aria-label="Toggle Main Menu" aria-controls="nav-holder">
Menu Button
</button>
<div id="nav-holder">
<nav id="primary-nav" class="horizontal-menu js-menu" role="navigation" aria-label="Main Menu">
<?php wp_nav_menu( array(
'theme_location' => 'top-menu',
'menu_id' => 'top-menu',
'container' => '',
'fallback_cb' => '__return_false',
) ); ?>
</nav>
</div>
Note that the aria-controls of the button do not need to point to a nav element. They can open/close anything. This allows for opening a div that potentially holds many menus etc.. All other aria attributes will be added for you.
I also added a class of horizontal-menu to the nav. This creates a horizontal menu that will go vertical at the breakpoint you specified. This class is not needed, as js will put it there. It is however recommended to add it because if javascript has been disabled it will still work.
CSS Changes
- The CSS now affects all menus not just the #primary-menu selector. Just make sure your nav element has js-menu class.
- Submenus are hidden with visibility and opacity on desktop as opposed to display: none. This allows for transitions.
- A js class of horizontal-menu is added and removed based on the breakpoint you created in the js instance. As mentioned above, this makes it easy to style the two separate views of the menu, which can get overly complicated.
- It is recommended to add horizontal-menu class to the nav element markup just in case there is no js. This will allow for a horizontal menu with a default media query of when to go vertical.
- A simple class of li.active can be used to decide how the submenus should appear. This class works whether the li was clicked, hovered, focused. It applies based on the screens capabilities.
NOTE: There is no css for how to hide/show the menu. When the menu button is clicked, aria attributes are applied, but not styled. It is up to the developer to decide how the menu appears. (flies in from side, opacity change etc...)
Alternate Designs
I tried to find the most common scenarios found on most sites I have made or seen and what is expected from a menu.
Benefits
Save 10+ hours making a menu :)
Possible Drawbacks
I don't see any...yet.
Verification Process
Tested on a WordPress site.
Checklist:
- [x] My code follows the code style of this project.
- [x] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] All new and existing tests passed.
If it has to be backwards compatible, I can do that... The biggest changes are the breakpoint accepts a simple unit e.g: 768px instead of a whole query like (min-width...) And the menu button is optional which means if someone does not add it as an option, it is considered not there and the button will be ignored.