'jQuery to scroll active horizontal menu item to the center
I am working on a responsive sub menu that on small screens will be scrollable horizontally instead of stacking the links. I can make that work. What I would like to do is center the active menu item on the current page. Im using wordress, so the class is already there .current-menu-item
. I have been attempting to use jQuery to calculate the center and scroll the menu item on page load, and it works in my jsfiddle, but not on an active website. I'm not certain that I am using the correct approach but here is what I am currently doing:
<div id="ds-sub-menu">
<ul id="menu-new-here" class="menu">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li class="current-menu-item"><a href="#">Link 3</a></li>
<li ><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
<li><a href="#">Link 6</a></li>
</ul>
</div>
jQuery(document).ready(function($) {
var totalWidth = $("#ds-sub-menu").outerWidth()
$('#ds-sub-menu ul').css('width', totalWidth);
var myScrollPos = $('#ds-sub-menu .current-menu-item').offset().left + $('#ds-sub-menu .current-menu-item').outerWidth(true) / 2 +
$('#ds-sub-menu .menu').scrollLeft() - $('#ds-sub-menu .menu').width() / 2;
$('#ds-sub-menu .menu').scrollLeft(myScrollPos);
});
#ds-sub-menu {
width: 100%;
max-width: 300px;
background: #000;
overflow: hidden;
}
#ds-sub-menu ul {
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
#ds-sub-menu li {
display: inline-block;
padding: 10px 14px;
text-align: -webkit-match-parent;
}
#ds-sub-menu li a {
color: #ccc;
}
#ds-sub-menu li.active a {
color: #fff;
}
My jsfiddle is a here
Solution 1:[1]
Ok, sorry for wasting everyone's time. This was a CSS issue.
In my fiddle, I set a max-width of 300px for the primary container so it would mimic a small device. I also did this in my website css, and it conflicted with the jQuery .outerWidth()
function because that was returning as 300px as well. I simply removed the max-width from the container element and now it works perfectly.
So full website code if anyone else ever wants to do something like this:
Wordpress Menu Sample
<!--Mobile Version -->
<div id="ds-mobile-sub-menu" class="ds-sub-menu">
<ul id="menu-new-here" class="menu">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li class="current-menu-item"><a href="#">Link 3</a></li>
<li ><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
<li><a href="#">Link 6</a></li>
</ul>
</div>
<!-- Desktop Version -->
<div id="ds-desktop-sub-menu" class="ds-sub-menu">
<ul id="menu-new-here" class="menu">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li class="current-menu-item"><a href="#">Link 3</a></li>
<li ><a href="#">Link 4</a></li>
<li><a href="#">Link 5</a></li>
<li><a href="#">Link 6</a></li>
</ul>
</div>
jQuery
jQuery(document).ready(function ($) {
if( $('#ds-mobile-sub-menu').length ){
// Dynamically set the width of #ds-sub-menu li by adding the widths of all the contained li's
var totalWidth = $("#ds-mobile-sub-menu").outerWidth()
$('#ds-mobile-sub-menu ul').css('width', totalWidth);
var myScrollPos = $('#ds-mobile-sub-menu .current-menu-item').offset().left + $('#ds-mobile-sub-menu .current-menu-item').outerWidth(true) / 2 + $('#ds-mobile-sub-menu .menu').scrollLeft() - $('#ds-mobile-sub-menu .menu').width() / 2;
$('#ds-mobile-sub-menu .menu').scrollLeft(myScrollPos);
$(window).on("orientationchange",function(){
var totalWidth = $("#ds-mobile-sub-menu").outerWidth()
$('#ds-mobile-sub-menu ul').css('width', totalWidth);
var myScrollPos = $('#ds-mobile-sub-menu .current-menu-item').offset().left + $('#ds-mobile-sub-menu .current-menu-item').outerWidth(true) / 2 + $('#ds-mobile-sub-menu .menu').scrollLeft() - $('#ds-mobile-sub-menu .menu').width() / 2;
$('#ds-mobile-sub-menu .menu').scrollLeft(myScrollPos);
});
}
});
The CSS
#ds-mobile-sub-menu {
display: none;
}
.ds-sub-menu {
background: #000;
text-align: center;
width: 100%;
}
.ds-sub-menu ul {
text-align: center;
padding: 20px 0;
display: block;
}
.ds-sub-menu li {
display: inline-block;
padding: 0;
position: relative;
}
.ds-sub-menu li a {
color: #818181;
font-family: Montserrat;
font-weight: 400;
text-transform: uppercase;
padding: 18px 14px;
}
.ds-sub-menu li.current-menu-item a, .ds-sub-menu li a:hover {
color: #fff;
}
Mobile Media Query This is a single sample of CSS to set the overflow to scroll and hide the scrollbar.
@media only screen and (max-width : 320px) {
#ds-desktop-sub-menu { display: none; }
#ds-mobile-sub-menu { display: block; }
.ds-sub-menu ul {
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
}
Other Notes This doesn't come at perfectly centered, but is in the ballpark. There are probably some more tweaks that could really fine tune things.
UPDATE I have made some additional tweaks in the css to get the centering perfected. Here are the changes:
remove padding and margin from the list-item add padding to the anchor
UPDATE #2 Upon using this feature a bit more, I have made some additional tweaks to make it better handle responsiveness for different devices and eliminate an error I was getting.
First: I was getting a jQuery error on pages that did not have the submenu. So I added the following line to only run the function if the sub-menu does exist.
if( $('#ds-mobile-sub-menu').length ){}
second: I noticed that if I rotated a mobile device, the function had already been run, so the calculated width no longer applied and the menu didn't look right. So I added a desktop class and a mobile class. The function actually only fires now on the mobile class and then I added the following function to recalibrate things on screen change:
$(window).on("orientationchange",function(){});
Now when you rotate a mobile device, or change your desktop screen to a smaller format, the appropriate menu will be displayed and the function will calculate the size of the menu based on the screen size.
I have updated the code to reflect these changes.
Solution 2:[2]
This line seems wrong:
var myScrollPos = $('li.active').offset().left + $('li.active').outerWidth(true) / 2 + $('.menu').scrollLeft() - $('.menu').width() / 2;
There isn't any li.active
. Should be then .current-menu-item
:
var myScrollPos = $('.current-menu-item').offset().left + $('.current-menu-item').outerWidth(true) / 2 + $('.menu').scrollLeft() - $('.menu').width() / 2;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | meshin |