Skip to content

Instantly share code, notes, and snippets.

@mrjman
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrjman/0d0b08cb1f239d0d3c75 to your computer and use it in GitHub Desktop.
Save mrjman/0d0b08cb1f239d0d3c75 to your computer and use it in GitHub Desktop.
jquery.scroll-nav plugin - scrolls to anchor on page and keeps track of active nav link
<!doctype html>
<html class="no-js">
<head>
<style>
a:hover {
color: green;
}
li.active {
color: red;
}
div {
border: 1px solid red;
height: 300px;
margin-bottom: 30px;
}
.nav {
position: fixed;
}
</style>
</head>
<body>
<ul class="nav">
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li>
<li><a href="#four">Four</a></li>
<li><a href="#five">Five</a></li>
<li><a href="#six">Six</a></li>
<li><a href="#seven">Seven</a></li>
</ul>
<div id="one">One</div>
<div id="two">Two</div>
<div id="three">Three</div>
<div id="four">Four</div>
<div id="five">Five</div>
<div id="six">Six</div>
<div id="seven">Seven</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="scripts/jquery-ui.js"></script>
<script src="scripts/jquery.scroll-nav.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>
(function($) {
$.fn.scrollNav = function(method) {
var defaults = {
activeClass: 'active',
activeSelector: 'li',
linkSelector: 'li > a',
easing: 'swing',
duration: 400,
offset: 0 // can be a number or a function to calculate offset
};
var instance = this;
var $instance = $(instance);
instance.settings = instance.settings || {};
var $window = $(window);
var methods = {
init: function(options) {
$.extend(instance.settings, defaults, options);
instance.$linkTargets = $instance.find(instance.settings.linkSelector);
instance.$linkTargets.on('click', function(e) {
e.preventDefault();
var $this = $(this);
instance.$scrollingTo = $($this.attr('href'));
var targetTop = instance.$scrollingTo.offset().top;
$('html, body').animate({"scrollTop": targetTop}, instance.settings.duration, instance.settings.easing);
return false;
});
methods.bind();
},
bind: function() {
$window.on('scroll.scroll-nav', helpers.doScroll);
$window.trigger('scroll.scroll-nav');
}
};
var helpers = {
doScroll: function() {
var scroll = $window.scrollTop();
if(instance.$scrollingTo !== undefined) {
if(mondo.math.approximately(scroll, instance.$scrollingTo.offset().top, 30)) {
$('html, body').stop(true, false).scrollTop(instance.$scrollingTo.offset().top);
instance.$scrollingTo = undefined;
}
}
var offsets = [];
instance.$linkTargets.each(function(index, el) {
var $el = $(el);
// get element that matches anchor tag
$target = $($el.attr('href'));
// short circuit if not found
if ($target.length <= 0) {
return;
}
var offset;
if (typeof instance.settings.offset === 'function') {
offset = instance.settings.offset();
}
else {
offset = instance.settings.offset;
}
offsets.push($target.offset().top + offset);
});
offsets = offsets.sort(function(a, b) {
return a - b;
});
if (offsets.length > 0) {
instance.$linkTargets.closest(instance.settings.activeSelector).removeClass(instance.settings.activeClass);
var $activeTarget = undefined;
for (var i = offsets.length - 1; i >= 0; --i) {
if (offsets[i] <= scroll) {
$activeTarget = instance.$linkTargets.eq(i);
break;
}
}
if ($activeTarget === undefined) {
$activeTarget = instance.$linkTargets.first();
}
$activeTarget.closest(instance.settings.activeSelector).addClass(instance.settings.activeClass);
// get the active targets anchor tag
var hash = $activeTarget.attr('href');
// switch the hash if it is different
if (scroll > 0 && window.location.hash != hash) {
// grab the linked anchor element
var $hashEl = $(hash);
// store the current id and unset it temporarily to
// stop the page from jumping when changing the hash
var id = $hashEl.attr('id');
$hashEl.attr('id', '');
window.location.replace(hash);
// reset the id on the anchor element
$hashEl.attr('id', id);
}
}
}
};
if (methods[method]) {
methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof(method) === 'object' || !method) {
methods.init.call(this, method);
} else {
$.error('Method: ' + method + ' does not exist');
}
return this;
};
})(jQuery);
jQuery(function($) {
$('.nav').scrollNav({
'duration': 1000,
'easing': 'easeOutQuad' // can use any default easing, or include jquery-ui easing to get more options
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment