Match Media not working correctly with JQuery

I am trying to make a responsive dropdown navigation menu in Jquery.

In desktop size the dropdown should appear on hover which is happening correctly.

In size less than 430px the hover should stop working and on click the dropdown should appear.

Now when I resize my browser from desktop to 430px, the hover still works.

$("nav li").hover(function(event) {
if( $("nav ul ul").css('display') == 'none' )
$(this).children("ul").slideDown("fast");
else {
$(this).children("ul").slideUp("fast");
}
event.stopPropagation();
});

if (window.matchMedia("(max-width: 430px)").matches)
{

$("nav > ul > li").hover(function(event) {
$(this).children("ul").css("display","none");
event.stopPropagation();
});

$("nav > ul > li").click(function(event) {
$(this).children("ul").slideToggle();
event.stopPropagation();
});

}

Please help. Thank you

matchmedia only runs when the page is loaded so you would need to refresh the page to stop the hover.

You don’t seem to need the first part of the script either as the following is working for me.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
ul {
	margin:0;
	padding:0;
	list-style:none
}
nav li ul {
	display:none
}
nav li:hover ul {
	display:block;
	position:absolute;
	top:100%;
	left:0;
	border:1px solid #000;
	background:#000;
	color:#fff;
	width:10em;
}
nav > ul > li {
	position:relative;
	float:left;
	background:#f9f9f9;
	border:1px solid #000;
	margin:0 -1px 0 0;
}
nav a{padding:10px 25px;display:block;}
.sub a{color:#fff;text-decoration:none;}
</style>
</head>

<body>
<nav>
  <ul>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
  </ul>
</nav>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script>
if (window.matchMedia("(max-width: 430px)").matches) {

    $("nav > ul > li").hover(function(event) {
        $(this).children("ul").css("display", "none");
        event.stopPropagation();
    });

    $("nav > ul > li").click(function(event) {
        $(this).children("ul").slideToggle();
        event.stopPropagation();
    });

}
</script>
</body>
</html>

If you want matchmedia to work when the page is resized then you would need to do as mentioned [at the end of this article] (http://www.javascriptkit.com/dhtmltutors/cssmediaqueries4.shtml) and add an event listener.

Although it seems to me that you probably wouldn’t want the desktop to stop hovering when the page is resized but really only when the page is opened at the small size to start with.

I also think it would be simpler and better to use a class on the nav element to produce the desktop hover and then simply remove that class in the matchmedia.

e.g.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
ul {
	margin:0;
	padding:0;
	list-style:none
}
nav li ul {
	display:none;
	position:absolute;
	top:100%;
	left:0;
	border:1px solid #000;
	background:#000;
	color:#fff;
	width:10em;
}
nav.hover li:hover ul {
	display:block;
}
nav > ul > li {
	position:relative;
	float:left;
	background:#f9f9f9;
	border:1px solid #000;
	margin:0 -1px 0 0;
}
nav a{padding:10px 25px;display:block;}
.sub a{color:#fff;text-decoration:none;}
</style>
</head>

<body>
<nav class="hover">
  <ul>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
  </ul>
</nav>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script>
if (window.matchMedia("(max-width: 430px)").matches) {
  	$("nav").removeClass('hover');
	
    $("nav > ul > li").click(function(event) {
        $(this).children("ul").slideToggle();
        event.stopPropagation();
    });
}
</script>
</body>
</html>

You can still add the event listener in if you want.

Remember though that tablets are bigger than 430px and they are touch only so you need ot check that they will work with the hover method you are using. These days I generally just use click dropdowns for all devices instead and it solves all the issues.

Thanks Paul.

OK I will look in to it. Thank you :slight_smile:

Here’s a working version with the event listener added.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
ul {
	margin:0;
	padding:0;
	list-style:none
}
nav li ul {
	display:none;
	position:absolute;
	top:100%;
	left:0;
	border:1px solid #000;
	background:#000;
	color:#fff;
	width:10em;
}
nav.hover li:hover ul {
	display:block;
}
nav > ul > li {
	position:relative;
	float:left;
	background:#f9f9f9;
	border:1px solid #000;
	margin:0 -1px 0 0;
}
nav a{padding:10px 25px;display:block;}
.sub a{color:#fff;text-decoration:none;}
</style>
</head>

<body>
<nav class="hover">
  <ul>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="http://www.google.com">test this one</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
    <li><a href="#">test</a>
      <ul class="sub">
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
        <li><a href="#">test</a></li>
      </ul>
    </li>
  </ul>
</nav>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script>
var mql = window.matchMedia("screen and (max-width: 580px)")
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){
        $("nav").removeClass('hover');

        $("nav > ul > li").click(function(event) {
            var thisChild = $(this).find('ul');
			$("nav ul ul").not(thisChild).slideUp();
			$(this).children("ul").slideToggle();
            event.stopPropagation();
        });
    } else{
		 $("nav > ul > li").unbind( "click" );
		 $("nav").addClass('hover');
		 $('ul.sub').removeAttr('style');
	}
}

</script>
</body>
</html>

wowww… thank you paul :slight_smile:

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.