In-page links (or, links that jump to specific areas of the current page) are definitely useful for lengthy or text-heavy sites, and often essential when these pages are consumed by screenreaders or "legacy" mobile devices. But they can also be disorienting for many reasons — did I just move up the page? Down it? With the instantaneous transition the browser provides by default, a user is left to guess.
I wouldn't be the first to suggest overriding this behavior with a scrolling effect that illuminates which direction you've traveled, and also how far. A global, automatic solution would be ideal. For animated effects, a robust JavaScript library can save a lot of time, and I'll use the popular jQuery library for this example. Out of the box, jQuery does not have this functionality, and although there is an appropriate plugin, I was determined to cobble together my own solution so as to avoid loading an additional plugin only to use it in this one instance.
A quick seach brought me to Learning jQuery, where there is a great solution I've shamelessly copied (with very minor modification). I will walk through this solution below, although I recommend reading the original breakdown at Learning jQuery.
$(document).ready(function() {
$('a[href*=#]').click(function() {
var target = $('a[name=' + this.hash.split('#')[1] + ']');
if (target.length) {
var targetOffset = target.offset().top - 2;
$('html,body').animate({scrollTop: targetOffset}, 'fast');
return false;
}
});
});
Attach a click event to every anchor element with an href
attribute beginning with a '#' (e.g. any in-page link).
$('a[href*=#]').click(function() { ... });
Get the link's destination on the page using its hash
property.
hash
refers to the portion of any URL that begins with '#'. Use this
in another selector to get the anchor element on this page with the
corresponding name
attribute. Save this as the target
variable.
var target = $('a[name=' + this.hash.split('#')[1] + ']');
If this element exists on the page (target
collection length
greater than zero), get the distance from the top of the page to this
element and save it as targetOffset
(note that I subtract 2 to give a
little bit of breathing room visually; this way the element doesn't
touch the top of the browser frame).
if (target.length) {
var targetOffset = target.offset().top - 2;
//...
}
Now use jQuery's built-in
animate()
method to scroll
the page itself (grabbing the html
or body
element in case the
browser is in
quirksmode).
$('html,body').animate({scrollTop: targetOffset}, 'fast');
Return false
because now you don't actually follow this link.
return false;
You can see this in action in many areas of this site as long as you have javascript enabled. For example, try clicking the "top ↑" link in the right-hand column.
It's of note that the
animate()
method takes a
variety of arguments. I've only supplied the target for scrollTop
and
the speed ("fast"), but it's a very powerful function. A third argument,
easing
, is available via a plugin, and can make the animation look
much more natural. In my case, however, I opted for less code overhead
and omitted this. The final argument, callback
, provides for some
interesting possibilities, but I also found it to be unnecessary for
this case.