UPDATE: To clear up some confusion I added a fiddle that demonstrates how it is supposed to work, but it is just missing the scrollspy: https://jsfiddle.net/kmdLg7t0/ How can I add the scrollspyto this fiddle so that the menu highlights when I'm on a specific section?
I created a fixed left menu that turns into an off-canvas menu at <992px in browser width for tablet and mobile. When I select the anchor link on a browser width >992px it closes the menu and navigates to the anchor link section.
Custom JQuery Code: This is my custom jQuery code that closes the Off-Canvas Menu when I click on an anchor link:
// close off-canvas menu and navigate to anchor
$('.navmenu-nav li a').on('click', function() {
$('body').removeClass('bs.offcanvas');
});
PROBLEM:
I decided to add a bootstrap offscrollspy and it works as intended after the browser width is greater than 992px, but when I resize the browser width to less than 992px this interferes with the Custom Jquery Code to close the menu and navigate to the anchor link.
Here's the Fiddle:
Bootstrap ScrollSpy causes issue with Off Canvas Menu and JQuery Code
My GUESS: I'm guessing the solution to this problem is to use jquery or javascript to prevent or remove the data-target=".navmenu" from activating when my screen is less than the <992px. Or we can find a way to only activate the scrollspy after >992px. I'm currently trying to figure this out, but I need someone who is a true expert in jquery to solve this dilemma.
Pre-Requisite:
JS:
$(document).ready(function () {
toggleOffcanvas($(window).width() <= 992);
});
// simulate modal opening
$('.nav-link').click(function() {
if ($(window).width() > 992) {
$('.backdrop').hide(0, false);
}
$('#navToggle').click();
});
$('.navmenu').on('show.bs.offcanvas', function() {
if ($(window).width() <= 992) {
$('.backdrop').fadeIn();
}
});
$('.navmenu').on('hide.bs.offcanvas', function() {
if ($(window).width() <= 992) {
$('.backdrop').fadeOut();
}
});
// close modal on resize
$(window).resize(function() {
if ($(window).width() > 992) {
$('.backdrop').hide(0, false);
$('body').removeClass('bs.offcanvas');
}
toggleOffcanvas($(window).width() <= 992);
});
// switch active navigation link onclick
$('.nav a').on('click', function() {
$('.nav').find('.active').removeClass('active');
$(this).parent().addClass('active');
});
// close modal when navigating to anchor
$('.navmenu-nav li a').on('click', function() {
$('body').removeClass('bs.offcanvas');
});
function toggleOffcanvas(condition) {
if (!! condition) {
$('.nav-link').attr('data-toggle', 'offcanvas');
} else {
$('.nav-link').removeAttr('data-toggle');
}
}
html:
<body data-spy="scroll" data-target="#myScrollspy" data-offset="50">
<div class="backdrop"></div>
<div id="myScrollspy" class="navmenu navmenu-default navmenu-fixed-left offcanvas-sm colornav ">
<a href="#" class="close" data-toggle="offcanvas" data-target=".navmenu">×</a>
<a id="navToggle" class=""><span></span></a>
<h4 class="navmenu-brand visible-md visible-lg visible-sm visible-xs" href="#">2017</h4>
<ul class="nav navmenu-nav">
<li class="active"><a class="nav-link" data-toggle="offcanvas" data-target=".navmenu" href="#january">Enero</a></li>
<li><a class="nav-link" data-toggle="offcanvas" data-target=".navmenu" href="#february">Msrs</a></li>
<li><a class="nav-link" href="http://www.jasny.net/bootstrap/examples/navmenu-reveal/">Jupiter</a></li>
<li><a class="nav-link" href="http://www.jasny.net/bootstrap/examples/navbar-offcanvas/">Off canvas navbar</a></li>
</ul>
</div>
<div class="navbar navbar-default navbar-fixed-top navbar-preheader">
<button type="button" class="navbar-toggle" data-toggle="offcanvas" data-target=".navmenu">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">navbar brand</a>
</div>
<div class="container">
<div class="page-header">
<h1>Navmenu Template</h1>
</div>
<p class="lead">This example shows the navmenu element. If the viewport is <b>less than 992px</b> the menu will be placed the off canvas and will be shown with a slide in effect.</p>
<p>Also take a look at the examples for a navmenu with <a href="http://www.jasny.net/bootstrap/examples/navmenu-push">push effect</a> and <a href="http://www.jasny.net/bootstrap/examples/navmenu-reveal">reveal effect</a>.</p>
<p class="space"></p>
<p id="january">January</p>
<p id="february">February</p>
</div><!-- /.container -->
</body>
CSS:
html, body {
height: 100%;
}
body {
padding: 50px 0 0 0;
}
.space {padding-bottom:900px;}
.backdrop {
background: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
bottom: 0;
width: 100vw;
height: 100vh;
z-index: 1040;
display: none;
}
.navbar-fixed-top {
background:#fff!important;
}
.navbar {
display: block;
text-align: center;
}
.navbar-brand {
display: inline-block;
float: none;
}
.navbar-toggle {
position: absolute;
float: left;
margin-left: 15px;
}
.container {
max-width: 100%;
}
@media (min-width: 1px) {
.navbar-toggle {
display: block !important; background:none!important; border:none !important; color:#f90 !important;
}
}
@media (min-width: 992px) {
body {
padding: 30px 0 0 300px;
}
.navmenu {
padding-top: 0;
}
.navbar-toggle {display:none!important;}
.close {display:none}
.navmenu-fixed-left {
z-index:0;
top: 48px;
bottom: 0; background:#fff!important;
}
}
.navbar-default .navbar-toggle .icon-bar{
background-color:#333;
}
.close {margin-right:10px; margin-top:10px;}
@media (max-width:991px) {
.navmenu-fixed-left {
z-index:1050;
top: 0;
bottom: 0; background:#fff!important;
}
}
.backdrop {display:none}
#january, #february {
text-transform: uppercase;
background-color: red;
text-align: center;
line-height: 90vh;
font-size: 5em;
height: 90vh;
color: white;
}
#february {
background-color: green;
}
The problem with the code is that data-target=".navmenu"
on menu items breaks the scrollspy plugin. Basically, scrollspy makes the connection between menu item and an element on the page via either data-target
property or href
property. Here is a part of it's source code:
return `${selector}[data-target="${target}"],` +
`${selector}[href="${target}"]`
Because of this you can't use data-target
on menu links to close the menu. You can use javascript to close the menu instead.
Here is updated link's HTML:
<li class="active"><a class="nav-link" href="#january">Enero</a></li>
<li><a class="nav-link" href="#february">Msrs</a></li>
And all the javascript you need:
$(document).ready(function () {
// Add the backdrop when menu is shown
$('.navmenu').on('show.bs.offcanvas', function() {
$('.backdrop').fadeIn();
});
// Remove the backdrop when menu is hidden
$('.navmenu').on('hide.bs.offcanvas', function() {
$('.backdrop').fadeOut();
});
// Hide the menu on menu item click
$('.nav-link').click(function() {
if ($(window).width() <= 992) {
$('.navmenu').offcanvas('toggle');
}
});
// Remove the backdrop if window is resized over the breakpoint
$(window).resize(function () {
if ($(window).width() > 992) {
$('.backdrop').fadeOut();
}
});
});
A complete working example:
https://jsfiddle.net/kmdLg7t0/5/
Finally you have to remove all href="#"
from link elements where they are not necessary. For example close menu button will take you back to #
even if you have navigated to #january
.
So things I did in total:
data-
attributes from linkshref=#
from linksEverything else is handled by plugins themselves.
By tying the scroll spy to a class, you can then toggle said class as needed. In addition, make sure to run the function once on page load to set initial state.
$('body').scrollspy({ target: '.scroll-spy' });
toggleScrollSpy($(window).width() <= 992);
// close modal on resize
$(window).resize(function() {
if ($(window).width() > 992) {
$('.backdrop').hide(0, false);
$('body').removeClass('bs.offcanvas');
}
toggleScrollSpy($(window).width() <= 992);
});
function toggleScrollSpy(condition) {
if (!!condition) {
$('#myScrollspy').addClass('scroll-spy');
} else {
$('#myScrollspy').removeClass('scroll-spy');
}
}
I would simply say when you animate or resize web page, make sure your coordinates top, left and height, width are carefully calculated. Because if they there is any change during resize it will show undesired positions. So its always good idea to examine coordinates and then alter dynamically them as the need arises.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With