I have a bit of javascript that smooth scrolls to any clicked #anchor-id (adaptation of this). For certain pages it throws a $target.offset(...) is undefined
error, and stops working, and I don't understand why.
I have done some testing and it seems to be correlating to the length of the page, as far as I can tell. Keeping all variables the same, only varying the amount of content, the bug occured (on the exact same page).
The weird thing is that I haven't been able to reproduce this effect on jsfiddle, it works fine over there, for every length. Does anyone know how to troubleshoot this bug? What could be the cause of it?
This is the javascript I'm using (I link to it at the bottom of every page, right before the </body>
tag and immediately after loading jquery 1.10.2):
$(document).ready(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
$('a[href*=#]').each(function() {
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
var $target = $(this.hash), target = this.hash;
if (target) {
var targetOffset = $target.offset().top;
$(this).click(function(event) {
event.preventDefault();
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
// commented line below because it adds a hash to the url and a history item
// location.hash = target;
});
});
}
}
});
// use the first element that is "scrollable"
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
});
This happens when the hash target does not exist. In HTML5 a valid hash target can only be written with an id.
So this will not work:
<a name="#hash">Hash</a>
But this will:
<a id="#hash">Hash</a>
Since using name="" isn't valid HTML5, #hash does not exist on the page so when you try to reference it with this:
var $target = $(this.hash) It returns undefined. Even links with valid hash targets won't smooth scroll if they are included after invalid ones because of this.