Function Friday #23: close your menu if a same-page anchor is clicked

Function Friday #23

Every Friday, I’m sharing code snippets that I use to customize WordPress. Feedback/suggestions are always welcome! For more information, check out the first post in the series.


Single-page websites and minimized-by-default menus are both really popular at the moment, and the combination of the two can cause an interesting problem.

When these menus are expanded, they often cover all or most of the screen. Clicking one of the items in the menu usually loads a different page, resetting the menu to its non-expanded state in the process.

Combine that with a single-page website, though, and you might only have anchor links in the menu. Clicking one of those menu items does not reload the page, but instead jumps down to an anchor on the same page.

You can end up with something like this:

Menu blocking page content

The page jumps down to the anchor, but because it doesn’t reload, the menu is still fully blocking most of your content. You’d have to scroll up and click the “Menu” bar to hide it again.

There is a better way! I’m not as comfortable with JavaScript as I am with PHP, but I managed to figure out a relatively simple solution.

(With that said, if you know of an even better way, please let me know in the comments!)

The code

// Toggle menu on same-page anchor click
var windowHref = window.location.protocol + '//' + window.location.host+window.location.pathname; // Don't include any existing anchors in URL
var menuItems = document.getElementsByClassName('menu-item');
for (var i = 0; i < menuItems.length; i++) {
    menuItems[i].onclick = function(e){
        var linkHref = this.getElementsByTagName('a')[0].href;
        if (linkHref.indexOf(windowHref) > -1) { // If the window's URL is found within the menu item's URL, toggle the menu
            menuToggle();
        }
    }
}

This code assumes that you’re handling the menu’s show/hide behaviour via a JavaScript function you created called menuToggle.

var windowHref = window.location.protocol + '//' + window.location.host + window.location.pathname; // Don't include any existing anchors in URL

This grabs the URL of the current page and stores it in a variable called “windowHref”. Using window.location.href here would be simpler, but you want to strip out any existing anchors before you try matching the URLs. For example, if you’ve already navigated to “http://example.com/about-us#introduction”, the next anchor you click (e.g. “http://example.com/about-us#team”) won’t be recognized as being on the same page if the anchor gets included in the URL you’re testing against.

var menuItems = document.getElementsByClassName('menu-item');

Next, you want to grab all of the menu items. On a WordPress site, they’re going to be list items with a class of “menu-item”.

for (var i = 0; i < menuItems.length; i++) {
    menuItems[i].onclick = function(e){
        var linkHref = this.getElementsByTagName('a')[0].href;
        if (linkHref.indexOf(windowHref) > -1) { // If the window's URL is found within the menu item's URL, toggle the menu
            menuToggle();
        }
    }
}

Now loop through all of those menu items. When one of them is clicked, get the href value of its child (because WordPress menu items are li elements containing an a element).

linkHref.indexOf(windowHref)

Zooming in a bit more, this takes the clicked menu item‘s URL (e.g. “http://example.com/about-us#team”) and searches within it for the current page‘s URL (e.g. “http://example.com/about-us”) using the indexOf function.

If the menu item’s URL does contain the current page’s URL, indexOf returns the exact position where it was found. All that really matters here is whether it returns -1 (i.e. the current page’s URL was not found anywhere within the menu item’s URL), or any number greater than -1 (i.e. it was found somewhere in there).

This is why you can’t just use window.location.href to get the current page’s URL above – “http://example.com/about-us#introduction” will not be found within “http://example.com/about-us#team”.

If it was found, you have a same-page anchor! So go ahead and fire off the function that closes your menu.

You can play with my (super simplified) demo below, or see all of the code here.

Where does it go?

This code would go in a .js file in your theme. More thoughts on code location are in the first Function Friday post.

Resources

Leave a Reply

Your email address will not be published.