I'm writing a script whose function is to convert a drop down menu to an accordion style menu depending on the screen width. To do this, the script swaps out class names based on the width. Visually, everything works as expected when the screen size changes. Also, if I open up the developer tools in chrome and adjust screen width, I can see the class names change in HTML.
Functionally, however, the browser seems to hold onto whatever class name it was when the page loaded. Here's the script:
$(function()
{
var screenWidth;
var screenMode;
var initial_check = 0;
var currentMode;
//check main window width
function checkWidth()
{
screenWidth = $(window).width();
//main size changes
if (screenWidth >= 769)
{
screenMode = "large";
changeDisplayMode("large");
}
else if (screenWidth < 769 && screenWidth > 350)
{
screenMode = "medium";
changeDisplayMode("medium");
}
else if (screenWidth < 350)
{
screenMode = "medium";
changeDisplayMode("medium");
}
//size change to stack View Cart items and search button
if (screenWidth < 603)
{
//show search magnify glass
}
}
//check width when entering page
checkWidth();
$(window).resize(checkWidth);
/////////////////////////////////////////////////////////////////////////////////
/////////// ///////
/////////// Code for navigation transition from drop down to accordion ///////
/////////// ///////
/////////////////////////////////////////////////////////////////////////////////
function changeDisplayMode(mode)
{
if (currentMode != mode)
{
if (mode == "large")
{
//set on first launch
initial_check = 1;
if (initial_check == 1)
{
$("#header_image").show();
$("nav").removeClass("nav_medium").addClass("nav_large");
$("div.main_menu_item_medium").removeClass("main_menu_item_medium").addClass("main_menu_item_large");
$("div.sub_menu_medium").removeClass("sub_menu_medium").addClass("sub_menu_large");
$("div.sub_menu_item_medium").removeClass("sub_menu_item_medium").addClass("sub_menu_item_large");
}
currentMode = "large";
}
else if (mode == "medium")
{
//set on first launch
initial_check = 1;
if (initial_check == 1)
{
$("#header_image").hide();
$("nav").removeClass("nav_large").addClass("nav_medium");
$("div.main_menu_item_large").removeClass("main_menu_item_large").addClass("main_menu_item_medium");
$("div.sub_menu_large").removeClass("sub_menu_large").addClass("sub_menu_medium");
$("div.sub_menu_item_large").removeClass("sub_menu_item_large").addClass("sub_menu_item_medium");
}
currentMode = "medium";
}
}
}
//hide inital dropdown menus
$('.nav_large li ul').hide();
$('.sub_menu_large').hide();
$('.nav_medium li ul').hide();
$('.sub_menu_medium').hide();
//navigation hover in large mode
$('.nav_large ul li').hover(
function()
{
$('.sub_menu_large', this).show();
console.log("large hover");
},
function()
{
$('.sub_menu_large', this).hide();
console.log("large hidden");
}
);
//navigation hover in medium mode
$('.nav_medium ul li').hover(
function()
{
$('.sub_menu_medium', this).show();
console.log("medium hover");
},
function()
{
$('.sub_menu_medium', this).hide();
console.log("medium hidden");
}
);
//accordion style clicks in medium mode
$('.nav_medium ul li').click (
function()
{
$('.sub_menu_medium', this).show();
console.log("clicked medium");
}
);
});
As you can see, there's a large and medium mode. If I load the page in large mode, adjust the browser to medium, and hover over an element, it still logs as it's in large mode. Same thing going from medium to large. As stated, I can see the HTML change correctly when viewing the source.
So, I guess I'm looking for some sort of refresh that doesn't reload the page? Is the class name cached somehow? I've tested this in chrome and firefox with identical results.
The problem is that you might be changing the size of the browser to test. However this approach will not work and will always give you the same width of the browser window no matter how much you reduce it.
In case you want to test it for different window sizes you need to do it through the Emulator of the browsers. In chrome you can press f12 and then Esc, you will get a tab named Emulation. set the screen size from there and test it
Related
I want to create a sidebar whose position is fixed only when the screen size is 992px and above. I've made the sidebar position fixed, but when the screen is 991 down the position is still fixed. I want when the screen size is 991px and down the position is relative.
but when i refresh the page, it works normally. Is there a strange behavior with the use of this javascript code?
Anyone can help me to solved this problem?
if ($(window).width() >= 992) {
var theLoc = 150;
var links = $('.d-submenu');
var content = $('.main-content');
$(window).scroll(function () {
console.log('scroll');
if (theLoc >= $(window).scrollTop()) {
if (links.hasClass('fixed')) {
links.removeClass('fixed');
content.removeClass('fixed');
}
} else {
if (!links.hasClass('fixed')) {
links.addClass('fixed');
content.addClass('fixed');
}
}
});
}
You need to add a event listener for page resize something like
$(window).on('resize', function(){
var win = $(this); //this = window
if (win.width() >= 992) { /* ... */ }
});
EDIT FOR FULL SOLUTION
function screenResize() {
if ($(window).width() >= 992) {
var theLoc = 150;
var links = $('.d-submenu');
var content = $('.main-content');
} REST OF YOUR CODE
// On page load call
screenResize();
// And recheck when window gets resized.
$(window).on('resize',function(){
screenResize();
});
I'm trying to make a collapsible submenu that, when there isn't enough space to fit all items, will throw overflowing items into a Bootstrap-style dropdown menu.
I'm doing this by checking if the submenu is greater than a certain height. If it's higher than this set height, it's considered overflowing and thus need to run it's function. However, the project I'm working on can't really have set heights on elements. These might change over time, and it will be a maintenance nightmare to go through all the code if something changes.
So how do I check if an element's height is higher than its own (I guess 'initial') height?
Setting if(menuHeight >= menuHeight) will cause a Maximum call stack size exceeded-error and crash the tab in Chrome.
Example:
var CollapseMenu = {
init: function(parent) {
var menu = parent;
var menuHeight = menu.height(); // Using jQuery here; vanilla JS could also work
if(menuHeight >= 64) // This is the set height I want to avoid
// ...
} else {
// ...
}
}
}
$(function() {
var submenu = $('.submenu');
if(submenu.length) {
CollapseMenu.init($('.submenu ul'));
}
$(window).resize(function() {
if(submenu.length) {
CollapseMenu.init($('.submenu ul'));
}
});
});
I have a filter on my website positioned in an aside with a class 'left-bar'. My site is responsive and i want the filter to move to the div with the class 'mobile-top-bar'.
With the first 'if' i check if the window isn't already below 992px and when that's the case the filter will be moved to the 'mobile-top-bar' (this works great)
if ($(window).width() < 992) {
$('#moveableFilter').prependTo('.mobile-top-bar');
}
With the second piece of code i've made a function that should move the filter back and forth, but that doesn't happen. The filter already disappears from the 'left-bar' when i slightly change the width of the window (when it's still above 992px) and when i change it below 992px it isn't present in the mobile-top-bar.
What did i do wrong?
$(window).on('resize', function(){
var win = $(this);
if (win.width() < 992) {
$('#moveableFilter').prependTo('.left-bar');
} else if (win.width() >= 992) {
$('#moveableFilter').prependTo('.mobile-top-bar');
}
});
It looks like you switched the cases around by accident. Try this:
$(window).on('resize', function(){
var win = $(this);
if (win.width() >= 992) {
$('#moveableFilter').prependTo('.left-bar');
} else if (win.width() < 992) {
$('#moveableFilter').prependTo('.mobile-top-bar');
}
});
... However, I do agree with the comment that says that it would be better not to use two different bars, but to move it with CSS media queries.
I'm encountering a slight problem with my navigation. When I resize my browser to check the mobile menu and click the 'header' a couple times for the dropdown menu, then resize my page back to a tablet or desktop size, my navigation disappears. This problem resolves itself if I delete this segment of code:
if ( width == GetWidth() ) {
return;
}
width = GetWidth();
But I need this section of code so the navigation does not disappear when I scroll down on mobile.
var screensize = document.documentElement.clientWidth;
$(document).ready(function(){
var isMobile = window.matchMedia("only screen and (max-width: 600px)");
if (isMobile.matches) {
$('#mobile_active li a').on('click',function() {
$('.Back a').text('Back');
$('#mobile_active li ul li a').slideToggle(150);
e.preventDefault();
});
}
$(window).resize(function(){
if ( width == GetWidth() ) {
return;
}
width = GetWidth();
if( $(window).width() < 600) {
$('#mobile_active').hide();
} else {
$('#mobile_active').show();
}
});
$('header').on('click', function() {
$('#mobile_active').slideToggle(500);
e.preventDefault();
});
});
Any advice or input would be of great help. Thank you.
I agree you should use media queries and javascript for this type of thing, but I think I have found the cause of your issue.
When in mobile mode you have a click event attached to your <header> with a slideToggle. This slideToggle sets an inline style of display:block; or display:none; on the #mobile_active after it animates; depending on wether its closed or opened. When you resize to desktop size the #mobile_active still has an inline style of display:none; which is why you can not see it any more.
It looks like you may have code to correct this on your resize event:
if( $(window).width() < 600) {
$('#mobile_active').hide();
} else {
$('#mobile_active').show();
}
I think it just needs placed before this code block:
if ( width == GetWidth() ) {
return;
}
width = GetWidth();
Which may be why when you remove it, it works
Hello! I've been learning jQuery for a little while now and am trying to sharpen my skills by creating a responsive website. I added a navigation bar, then a big slider, and below it is the main content of the website. Right now, jQuery (as both the menu background and the main background are black) adds a class to the navigation bar in order to turn it white as soon as you scroll past the slider (which has a height of 550px), so it will be easier to read.
Here's the thing: I want jQuery to add that class depending on the width of the window. If it's less than 600px wide, I want the class to be added automatically. Otherwise, I want jQuery to add it as soon as you scroll past the slider (since I hide it when the window is less than 600px wide). My code is below, and it works just fine if I resize the window and then refresh the page, but I want it to add the class dynamically. Do you think it is possible?
I hope I made myself clear (English is not my first language). Let me know if you need me to explain things better! Thank you in advance. :)
if ($(window).width() > 599 ) {
$(window).scroll(function() {
if ($(window).scrollTop() >= 550) { //if you scroll past the slider
$("#main nav").addClass("white-menu");
} else {
$("#main nav").removeClass("white-menu"); //so it turns black again
}
});
} else {
// add it automatically (the slider is hidden):
$("#main nav").addClass("white-menu");
};
you can use all the code inside scroll event
$(window).scroll(function() {
if ($(this).scrollTop() >= 550 && $(this).width() <= 599) { //if you scroll past the slider
$("#main nav").addClass("white-menu");
} else {
$("#main nav").removeClass("white-menu"); //so it turns black again
}
});
a similar DEMO
about resize you can use
$(window).on('resize',function() {
$("#main nav").removeClass("white-menu");
});
on window resize the code will remove the class till user scroll then the scroll event will fire after user scrolling
or instead of all of that you can just use
$(window).on('scroll resize',function() {
if ($(this).scrollTop() >= 550 && $(this).width() <= 599) { //if you scroll past the slider
$("#main nav").addClass("white-menu");
} else {
$("#main nav").removeClass("white-menu"); //so it turns black again
}
});
DEMO
.scroll allows you to listen to event, if you only listen when the window is the correct size, this listener won't get triggered if that changes, so I changed it around a bit:
$(window).scroll(function() {
if ($(window).width() > 599 ) {
if ($(window).scrollTop() >= 550) { //if you scroll past the slider
$("#main nav").addClass("white-menu");
} else {
$("#main nav").removeClass("white-menu"); //so it turns black again
}
}
});
Like Brian mentioned you should use CSS for this other case:
#media (max-width: 600px) {
#main nav {
// white-menu styles here
}
}
For reference the JS way would be:
$(window).resize(function() {
if ($(window).width() <= 599 ) {
$("#main nav").addClass("white-menu");
}
});
It also might be worth thinking about doing a throttle/debounce on these event listeners. They will get called a lot and if your JS starts to do anything more complicated you will see a performance hit. This example uses the underscore library:
var onScroll = function() {
if ($(window).width() > 599 ) {
if ($(window).scrollTop() >= 550) { //if you scroll past the slider
$("#main nav").addClass("white-menu");
} else {
$("#main nav").removeClass("white-menu"); //so it turns black again
}
}
}
// Don't run until the window has stopped being resized for at least 50ms
var debouncedOnScroll = _.debounce(onScroll, 50);
$(window).scroll(debouncedOnScroll);
See http://underscorejs.org/#debounce
Interesting. I used your code in a fiddle and it worked find. As it's state in another answer, the improve of your code will be using the scroll function to wrap all the actions:
$(window).scroll(function() {
$("#main nav").toggleClass("white-menu", ($(window).scrollTop() >= 550 && $(window).width() <= 599));
});