Disable jQuery Dropdown for Mobile - javascript

My website has had nav dropdowns that I made with CSS but I've recently changed it to jQuery so it's animated. When it was CSS I was able to disable the dropdowns on the smallest breakpoints for mobile. But with jQuery I don't know how to do that. This is my dropdown code. What can I do to it to make it disable when the viewport gets small enough?
$(document).ready(function() {
$('.nav > li').mouseenter(function() {
$(this).children('.nav-content').slideDown(200);
});
$('.nav > li').mouseleave(function() {
$(this).children('.nav-content').slideUp(200);
});
});
This is the website as it is now:
http://mattboy115.github.io/scarymonkeyshow/index.html

You can check the size of the screen with $(window).width() and $(window).height()
So something like
$(document).ready(function() {
if($(window).width() > 800){
$('.nav > li').mouseenter(function() {
$(this).children('.nav-content').slideDown(200);
});
$('.nav > li').mouseleave(function() {
$(this).children('.nav-content').slideUp(200);
});
}
});

The answers given will work, but I'd recommend making a second nav for mobile and using media queries to make the right one show.
Just real simple HTML:
<div class="desktop-nav">
[nav code]
</div>
<div class="mobile-nav">
[mobile nav code]
</div>
then CSS:
#media screen and (min-width: [X]px) {
.mobile-nav {
display: none;
}
}
#media screen and (max-width: [X]px) {
.desktop-nav {
display: none;
}
}
then your jquery is solved by just applying the mouseenter to .desktop-nav:
$(document).ready(function() {
$('.desktop-nav > li').mouseenter(function() {
$(this).children('.nav-content').slideDown(200);
});
$('.desktop-nav > li').mouseleave(function() {
$(this).children('.nav-content').slideUp(200);
});
});

I am uncertain if you are looking to do this at a specific size or if you want it for mobile. For example you can use modernizer to detect if touch is enabled on the device:
Using Modernizr to test for tablet and mobile - Opinions wanted
you can also check user agents to match device types and apply your code that way:
What is the best way to detect a mobile device in jQuery?
You can then apply if it does or doesn't match your conditions based on your detection..

Related

Click handler interferes with CSS hover state

On large screens, I want dropdowns to appear on hover, but on mobile I want to arrange them like accordions.
My jQuery is conflicting with my CSS. On mobile, clicking the li creates all kinds of problems: the event fires over and over, and if I resize to larger viewport, the dropdown remains open and the :focus and :hover rules are disabled.
Sass
// If bigger screen, show the submenu on hover or focus
ul.sub {
display: none;
}
body.desktop {
li.dropdown:hover,
li.dropdown:focus {
> ul.sub {
dispay: block;
}
}
}
JavaScript
if ($('body.desktop').length < 1) {
$('li.dropdown > a').on('click', function(e){
$(this).parent().find('.dropdown-menu').slideToggle('fast');
e.preventDefault();
});
} else {
return false;
}
The problem was the style="display:none;" rule applied by the .slideToggle() method. I needed to devise a way to override this on larger viewports.
JavaScript
$(window).resize(function(){
if (window.innerWidth > 795 ) {
$('.dropdown-menu').removeAttr('style');
}
});
Then, to stop the event from firing again and again, hat-tip to this solution:
$("li.dropdown").unbind().click(function() { ... });

Media Query conflicts with $(window).resize()

I've got a left nav div that hides via media query at < 768 and a filter button that displays at < 768. When you click the filter button it uses JQuery to toggle the display of the left nav via show()/hide(). When the window is resized >= 768 I use JQuery to set the display of the left nav back to show.
As I said, my media query handles hiding the left nav when the window width goes below 768, but the problem is it only fires if I have not clicked the filter button. Once I size it under 768 and then click the filter button to turn it on and then click it again to turn it off and then size up over 768 and then back down the left nav is still there. It's like the media query no longer works for the display:none attribute. There are other css properties I change in the media query like width and color and those still work, but it's no longer hiding the div.
I've simplified the code to illustrates the problem.
HTML
Button
<div id="navLeft">NavLeft</div>
CSS
#navLeft {
background-color:orange;
}
#filterButton {
background-color:silver;
display: none;
}
#media only screen and (max-width: 300px) {
#navLeft {
display: none;
}
#filterButton {
display: inline;
}
}
JS
$(window).resize(function()
{
var $theWindowSize = $(this).width();
if($theWindowSize > 300)
{
$('#navLeft').show();
}
});
// Filters
$('#filterButton').bind('click',function(event)
{
event.preventDefault();
if ($('#filterButton').hasClass('filtersActive'))
{
$('#navLeft').hide();
$('#filterButton').removeClass('filtersActive');
}
else
{
$('#navLeft').show();
$('#filterButton').addClass('filtersActive');
}
});
Here's the fiddle. To replicate the behavior follow the steps below.
https://jsfiddle.net/athcy8fL/
1) Resize the width of the Result viewport several times under and above 300px before clicking anything and you'll see everything works as planned. Under 300px the button comes on and the NavLeft div hides. Over 300px and the Button hides and the NavLeft shows
2) Size the Result viewport below 300px and click the Button link. The NavLeft div should appear. Good.
3) Size the Result viewport above 300px and the Button hides. Good.
4) Size the Result viewport below 300px, the NavLeft should hide but it does not. Not Good.
Why doesn't the media query work after using Javascript to alter its display property?
The problem is that when you call .show() in an element that is not already visible, jquery will add an inline style to show the element and override your css, causing the media-query not to work.
I modified your code a little bit to take the inline-style priority into account
http://jsfiddle.net/yjs3fou7/
basically I changed the resize function:
$(window).resize(function()
{
var $theWindowSize = $(this).width();
if($theWindowSize > 300)
{
$('#navLeft').show();
$('#filterButton').removeClass('filtersActive')
} else {
if (!$('#filterButton').hasClass('filtersActive'))
$('#navLeft').hide();
}
});
inline styles have more priority than id or class styles according to css specificity rules so once you start manipulating things from javascript you must remember it may cause your css to stop being applied
The problem is the use of inline styles which has more specificity than the css rules.
$(window).resize(function() {
var $theWindowSize = $(this).width();
if ($theWindowSize > 300) {
$('#navLeft').removeClass('show');
$('#filterButton').removeClass('filtersActive');
}
});
// Filters
$('#filterButton').bind('click', function(event) {
event.preventDefault();
$('#filterButton').toggleClass('filtersActive');
$('#navLeft').toggleClass('show', $('#filterButton').hasClass('filtersActive'));
});
#navLeft {
background-color: orange;
}
#filterButton {
background-color: silver;
display: none;
}
#media only screen and (max-width: 300px) {
#navLeft {
display: none;
}
#filterButton {
display: inline;
}
#navLeft.show {
display: block;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Button
<div id="navLeft">NavLeft</div>
Demo: Fiddle

how to disable mouseout visibility="hidden" effect for medias smaller than 768px?

I am pretty new at Javascript. I created this effect where text appears under an image icon when the user hovers over it. I would like the effect to only work when the screen is over 768px and for the text to just stay visible at all times when viewed on smaller devices. I've tried using different variants of
if (screen.width < 768px) {}
and
#media all and (min-width: 768px) {} else {}
to control the effect to my liking but without any luck. Help???
Here is my code:
<section id="s1">
<h1><a href="web/services.html">
<img src="images/ICON-TRANSCRIPTION.png" class="hover"></a></h1>
<p class="text">TRANSCRIPTION</p>
</section>
<script>
$('.hover').mouseover(function() {
$('.text').css("visibility","visible");
});
$('.hover').mouseout(function() {
$('.text').css("visibility","hidden");});
</script>
You do not need any JS to do this. The easiest way to accomplish this is to define the media query to be what you desire, set the element to visibility: hidden; and then add a hover rule to change the visibility attribute.
The visibility would be visible by default (on smaller screens), then set to hidden by the media query with the added hover functionality for larger screens.
#media all and (min-width: 768px) {
.hover { visibility: hidden; }
.hover:hover { visibility: visible; }
}
If you must do it via JS(this can be accomplished with CSS media queries), first you should get the width of the window and set it as a variable, then you can set up your conditional statement like so:
function mouseVisibility() {
var w = $(window).width();
if (w > 767) {
$('.hover').mouseover(function() {
$('.text').css("visibility","visible");
});
$('.hover').mouseout(function() {
$('.text').css("visibility","hidden");});
}
}
mouseVisibility();
Additionally, you should fire the function again if the user resizes the browser window:
$(window).resize(function() {
mouseVisibility();
});

Javascript override of media query

I'm creating a responsive site. I have a media query set up so that when the screen width drops below 768 px a class (lets call it "hiddenClass") is hidden. Then I implement Javascript to toggle this class into view on a button click. The problem I'm running into is that javascript seems to override the media query. So if I shrink the screen below 768px the "hiddenClass" disappears....then I click the button which displays the "hiddenClass".....then click the button once more to hide it on the smaller device again.....now I expand the window and the "hiddenClass" stays hidden even after it gets to the 768px. If I take out the javascript and shrink the window the "hiddenClass" performs like it should...which tells me javascript is overriding it.
Is there a CSS fix to this? I know I could always check for a window resize event in javascript to display the hiddenClass after it reaches 768px. Was just wondering if this can be handled with CSS....or if javascript is the way to fix it.
Update JSfiddle with JS commented out so you can see how it should work...then add in the JS to see the issue described above. The button is the 'menu' navigation element when you shrink the screen down and "hiddenClass" would be the "menu" class in the li's:
http://jsfiddle.net/or5vy17L/1/
HTML:
<ul>
<li class="menuButton">- Menu -</li>
<a href="index.html">
<li class="menu" >
Home
</li>
</a>
<a href="instagram.html">
<li class="menu" >
Instagram
</li>
</a>
<li class="menu">Clients</li>
<li class="menu">Nutrition</li>
<li class="menu">About Me</li>
<li class="menu">Contact</li>
</ul>
css:
li {
display:inline;
color:$font-color--nav;
cursor:pointer;
font-size:1.5em;
padding: .7em .7em .7em .7em;
//for space between margins
margin-right:-4px;
border-radius:.5em;
}
ul {
text-align:center;
}
.menuButton {
display:none;
}
#media (max-width:768px) {
ul {
padding:0px;
}
li {
display:list-item;
border:1px solid white;
padding:.2em .2em .2em .2em;
border-radius:0px;
}
.menu {
display:none;
}
.menuButton {
display:list-item;
}
}
javascript:
/****
$('ul').on('click', '.menuButton', function() {
$('.menu').slideToggle();
});
****/
The .hiddenclass is staying hidden because it is a inline style, and inline styles override nearly all other styles. You have two options, one is to override the inline style with a CSS, as described in this CSS Tricks post:
<div style="background: red;">
The inline styles for this div should make it red.
</div>
div[style] {
background: yellow !important;
}
JSFiddle Demo
According to this article, this CSS solution works in:
Internet Explorer 8.0
Mozilla Firefox 2 and 3
Opera 9
Apple Safari, and
Google Chrome
Or, use JS or JQuery to remove the inline style when the screen is resized:
$(window).resize(function(){
if($(this).width() >= 768){
$('.hiddenclass').show();
}
else{
$('.hiddenclass').hide();
}
});
JSFiddle Demo
I seem to have come across this issue myself and following the advice here, I've come up with this solution:
window.onresize = function() {
var menu = document.getElementById('nav').getElementsByTagName('ul')[0];
if(window.innerWidth >= 1024) menu.style.display = '';
};
function toggleMenu() {
var menu = document.getElementById('nav').getElementsByTagName('ul')[0];
var link = document.getElementById('nav').getElementsByTagName('a')[0];
if(menu.style.display == 'block') {
menu.style.display = 'none';
link.innerHTML = '▼';
}else{
menu.style.display = 'block';
link.innerHTML = '▲';
}
}
Explanation:
The toggleMenu() function controls the display/hiding of the menu, and the issue presented itself after resizing the window from < 1024px (drop-down style menu) to > 1024px, my normal "desktop" menu disappeared completely. Given that JavaScript inserts styles inline (i.e. as a element attribute, ) then on a resize of 1024 or higher, this inline style should be gone.
Problem fixed.

iOS click is activating parent anchor of dropdown menu

Iv run out of solutions that I can think of or find for this problem. I'm working on a fixed to the top of the page. The left side has a anchor that takes you to the top of the page, if hovered over it will show other external links. The right side is a list of page sections with anchors to scroll you to them.
this all works fine on desktop as hover and click are separate events, but on an ipad they are they same. On an iPad you should be able to touch the "Product List" list item and have the drop down menu appear. If touched again it will take you back to the top. Right now when you touch it will take you back to the top and display the hover.
Here is a jsfiddle recreating the code and issue. http://jsfiddle.net/hyaTV/5/
HTML
<ul class="one">
<li><a class="intrapage" href="#stage">Product Title</a>
<ul>
<li>other product</li> <!-- link that goes to different page -->
<li>other product</li> <!-- link that goes to different page -->
</ul>
</li>
</ul>
<ul class="two">
<li><a class="intrapage" href="#section_one">birds</a></li> <!-- goes to Birds section -->
<li><a class="intrapage" href="#section_two">bees</a></li> <!-- goes to bees section -->
</ul>
CSS
ul.one{float:left;list-style:none;}
ul.one ul{display:none;}
ul.one > li:hover ul{display:block;}
/* styling for right side nav */
ul.two{float:right;list-style:none;}
ul.two li{display:inline-block;}
JS
// scrolls window to element id with easing
$(".intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
});
You could use iOS :hover issue to your advantage. I believe by changing your CSS to
ul.one > li ul { display: none; }
ul.one > li:hover ul { display: block; }
That said, above problem doesn't exist on other mobile OS. there're no way to mouse out on iOS.
It's better to detect if user is on mobile device and add .mobile with javascript to <body> then toggle the sub-menu on click events.
CSS
ul.one > li:hover ul, ul.one > li.hover ul { display: block; }
JS
$('body.mobile ul.one > li').click(function(e) {
$(this).toggleClass('hover');
});
I came up with a solution which appears to work. It will require your page to include the Modernizr JS to check if touch is supported or not.
JS
if (document.addEventListener) {
document.addEventListener("touchstart", function(){}, true);
}
if($('html').hasClass('touch')){
$('.one > li').click(function(e){
if($(this).hasClass('hover')){
// $(this).removeClass('hover');
} else {
$(this).toggleClass('hover');
}
});
$('html').bind('touchstart', function(){
if($('.one > li').is(':hover')){
// do nothing
} else {
$('.one > li.hover').removeClass('hover');
}
});
$('.one a.intrapage').click(function(event){
if($('.one > li').hasClass('hover')){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
} else {
event.preventDefault();
}
});
$(".two .intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
});
} else {
$(".intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top - 50}, 850);
return false;
});
}

Categories