I am in the process of converting an existing Joomla website to WordPress (without altering the look) and making it responsive. I am working on the primary dropdown menu for device widths less than or equal to 420px.
I am using jQuery to make an accordian effect with the menu, but the sub-menu won’t stay open when I click on the parent item.
What I have so far can be seen at http://jaybeeweb.com/restoreWP . (Please note that I have not yet dealt with the menu for widths between 421px and 999px.)
Also, its initial state is fine when I open the site on my phone, but when I open the site on my laptop, then drag the window down to 420px, the submenus are visible until I refresh the page. I’m not sure if that will be an issue on the live site.
For the first problem, it’s not staying open because when you click on it you’re actually navigating to that page. Underneath “slideToggle” add return false. Returning false within a click event will prevent the event from bubbling up - effectively canceling the hyperlink:
$('#main-navbar .menu-item-has-children').click(function() {
$(this).children('ul').slideToggle('slow');
// Prevents nagivating to the page
return false;
});
(If you want to be able to actually navigate to the parent menu instead of expanding it, a little more logic will be needed.)
For the second problem, your code is only checking for the window width once onLoad. Wrap everything in a window.resize() event:
// Accordian for Primary Navigation Menu in Mobile phones
$(window).resize(function(){
if (window.innerWidth < 500) {
$('#main-navbar .menu-item-has-children ul').hide();
$('#main-navbar .menu-item-has-children').click(function() {
$(this).children('ul').slideToggle('slow');
// Prevents nagivating to the page
return false;
});
}
// NOTE: adding .resize() here with no callback will force this event to run once
// This is good because we want to check when the document loads
}).resize()
Thank you, @OzRamos. That fixed the second issue, but my submenu is still closing as soon as it opens. I have added the return false to my jQuery:
// Accordian for Primary Navigation Menu in Mobile phones
$(window).resize(function() {
if (window.innerWidth < '421') {
$('#main-navbar .menu-item-has-children ul').hide();
$('#main-navbar .menu-item-has-children').click(function() {
$(this).children('ul').slideToggle('slow');
// prevents navigating to the page
return false;
});
}
}).resize();
The parent item will have no content of its own, so I won’t need to navigate to that, just use it to open the sub-menu. But if the client decides to change this, what code would I have to add to make the parent item open its page? Would you use a single click for that, and a double-click for opening the sub-menu?
I moved the toggle outside the resize event, that should get rid of the open/close issue.
As for the nav issue I wouldn’t do double-click, most users probably wouldn’t know to double click it (I wouldn’t). Instead you could do something like:
// If the submenu is closed, open it.
// If it's not visible the we return false, canceling the navigation
if (!$(this).children('ul').is(':visible')) {
return false;
}
Another option is if you click on the arrow then it expands but if you click on the word it navigates to it.
Edit: fixed the last code block a bunch of times…it’s past midnight here
Thanks. It’s getting really late here, so I will try this first thing in the morning and let you know. By the way, I still want the slideToggle() to only work for browser windows 420px or less.
I’m back to working on this, @OzRamos. It looks like your conditional is having the submenu show if the browser width is not less than 421px. I don’t want this script to affect anything above the width of 420px. I have a CSS dropdown menu working for wider devices.[quote=“OzRamos, post:4, topic:232195”]
if (window.innerWidth < ‘421’) {
$(‘#main-navbar .menu-item-has-children ul’).hide();
} else {
$(‘#main-navbar .menu-item-has-children ul’).show();
}
[/quote]
So for the widths where I want the accordian menu to work, I hide the sub-menus to begin with. Then when the parent menu item is clicked, I want the sub-menu of that item to open and stay open.
Is it impossible to have the click open the submenu instead of navigating to the page? There will never be a unique page linked to from the parent item - it will just go to the first page in the sub-menu.
If your support is only modern browsers (IE11+) then you can use matchmedia and avoid resize() altogether. It works just like media queries but in javascript.
You also need to disable the hover from working when you are slideToggling as it seems to break the effect.
This works for me when i copied your page locally.
<script>
jQuery(document).ready(function($) {
var mql = window.matchMedia("screen and (max-width: 420px)")
mediaqueryresponse(mql) // call listener function explicitly at run time
mql.addListener(mediaqueryresponse) // attach listener function to listen in on state changes
function mediaqueryresponse(mql) {
if (mql.matches){
$('#main-navbar').removeClass('desktop');
$('#main-navbar .menu-item-has-children ul').hide();
$('#main-navbar .menu-item-has-children > a').click(function() {
$(this).next('ul').slideToggle('slow');
// prevents navigating to the page
return false;
});
} else{
$('#main-navbar').addClass('desktop');
$("#main-navbar .menu-item-has-children > a").unbind( "click" );
$('#main-navbar .menu-item-has-children ul').removeAttr('style');
}
}
});
</script>
(Bear in mind I mainly copied the mediaqueryresponse code from somewhere else as I;m not that advanced with JS )
In your original css I added the desktop class to the #main-navbar hover rule so that it doesn’t interfere when you want to click.
i.e.
#main-navbar.desktop ul li:hover ul {
display: block;
}
You must alter the original or remove it. This was the original rule.
#main-navbar ul li:hover ul {
display: block;
}
If you leave that last rule in place it will confuse things when you only want the click action.
Lastly you need to add the following media query after the original css to put the nav back in the flow rather than being absolute for the accordion.
@media screen and (max-width:420px){
#main-navbar ul li ul{position:static!important;}
}
I had originally envisioned the dropdown pushing the other top menu items below it, but I like this way better. It takes up less space. Do you think it would be intuitive for the user to know to click a second time to close the accordian and reveal the rest of the main menu?
There were still a couple of issues at the start:
The links in the dropdown didn’t seem to take the user to the new pages.
After I click once, the dropdown seemed to take on a life on its own and opens and shuts twice.
I tested it a second time, and it seems to be working fine. Thank you.
They seem to be working ok for me once I cleared cache.
You may have to add classes dynamically and style the open menu item and submenus a slightly different colour to make it look better.
I think its too confusing the way you have it now and on mobile that will just confuse. The version I gave you was more like the accordion and much easier to navigate. If you want an absolute dropdown effect then you will need to style the submenu with some depth effect (shadow perhaps and slightly smaller) to make it look like its on top and not just a continuation of the current menu.
That depends on the design and it looks to me as though your menu needs to change at 600px rather than 420px. You can’t afford ot let the desktop menu wrap so the change will need to occur at around 600px which I think is fine.
I would also initially hide the menu inside a hamburger menu so that it doesn’t eat into the page on small screens.
Okay. My original plan was to make the menu and its text fluid up to a point (not letting the text get too small) in the middle widths so that I wouldn’t have to resort to the full-width items too soon.
I agree with the hamburger icon - that is my next step.