Post Archive
› October 16, 2005
A (slightly) better technique for "Back to Top" links.
Until recently, I never had the occasion to employ links that scroll the browser viewport back to the top of the page. When a client requested them however, I had to look up how to make them. I didn't like the options I found:
- use an empty, named anchor somewhere near the top of the page (
<a name="top"></a>),
OR - use an
idattribute on some element near the top of the page (id="top")
Combined with a link whose href is a fragment identifier (<a href="#top">Back to top</a>), these constructs produce the desired result. But the overhead—at least to my delicate sensibilities—is undesirable:
- Extra markup cruft
- Unsightly fragment on the end of the URL after the link is clicked. Unlike other fragments,
#topis useless when the URL is bookmarked.
A bit of JavaScript in an unobtrusive fashion solves the problem:
<a href="#" onclick="window.scrollTo(0,0); return false">Back to Top</a>
Browsers with JavaScript turned on move to the top of the page without relying on extra tags or leaving a fragment in the address bar. Others fall back to the default link behavior. Notice the fragment is still there in the href, but it is now empty. I found that an empty fragment is interpreted by most browsers as link to the top of the page (even Lynx!). Opera is a notable exception.
Not being one to leave well enough alone, I just had to take this idea to its logical conclusion, namely, adding a "smooth scrolling" behavior. Here is the function:
function backToTop() {
var x1 = x2 = x3 = 0;
var y1 = y2 = y3 = 0;
if (document.documentElement) {
x1 = document.documentElement.scrollLeft || 0;
y1 = document.documentElement.scrollTop || 0;
}
if (document.body) {
x2 = document.body.scrollLeft || 0;
y2 = document.body.scrollTop || 0;
}
x3 = window.scrollX || 0;
y3 = window.scrollY || 0;
var x = Math.max(x1, Math.max(x2, x3));
var y = Math.max(y1, Math.max(y2, y3));
window.scrollTo(Math.floor(x / 2), Math.floor(y / 2));
if (x > 0 || y > 0) {
window.setTimeout("backToTop()", 25);
}
}
And here is the modified link:
<a href="#" onclick="backToTop(); return false">Back to Top</a>
You can see the effect here. Overkill? Perhaps. But I like simple uses of JavaScript such as this that make the web experience a bit more enjoyable.
Comments
1. October 16, 2005 12:39 AM
2. October 16, 2005 01:36 AM
David Lindquist Posted…
Except then you have this problem. I've never understood the aversion to (little bits of) inline JavaScript.
3. October 16, 2005 02:24 AM
David Lindquist Posted…
OK, I give:
window.onload = function() {
if (!document.getElementsByTagName)
return;
var a, i = 0;
while ((a = document.getElementsByTagName("a")[i++])) {
if ("#" == a.getAttribute("href")) {
a.onclick = function() { backToTop(); return false; }
}
}
}
Not the best way to attach the onload, but you get the idea.
4. October 16, 2005 06:10 AM
Jim Posted…
Um, so basically this breaks for anybody using Opera who has Javascript disabled? Because you don't like to see #top in your bookmarks? You have your priorities wrong. href="#" is commonly implemented by browsers as "back to top", but it's non-standard and liable to break. By all means, use smooth scrolling, but don't actively break things simply to make URLs look a little prettier.
5. October 16, 2005 06:30 AM
6. October 16, 2005 06:35 AM
7. October 16, 2005 08:53 AM
Jacob Stetser Posted…
Jim,
There are published standards and de facto standards. Sometimes, when a de facto standard is not actively detrimental to use, newcomers and/or "outlying" players should adopt the behavior in common use.
I realize that the authors of Opera enjoy being pedantic about standards, but conforming only to the published standards really isn't enough.
8. October 16, 2005 09:05 AM
Lon Posted…
Scanning is bad; it is likely to fail if your content is dynamic.
In my opinion the easiest way to do this is to attach an onclick handler on the document. The handler has to check whether the click was inside an anchor having a hash for its href. Easy.
9. October 16, 2005 10:23 AM
Jim Posted…
Jacob,
Whether Opera is correct or not in not implementing this behaviour is another matter entirely. The answer is irrelevant to the topic at hand; if Opera are wrong to not implement this, it doesn't mean that the code is any less fragile, or any fewer people will see the links break.
10. October 16, 2005 02:19 PM
Erik Arvidsson Posted…
This breaks the history. If a user clicks on the link I expect to be able to hit back to get back to where I was reading the page.
Some simple ideas:
11. October 16, 2005 03:13 PM
12. October 16, 2005 03:26 PM
Giorgio Martini Posted…
Pages not working for the 7% with JavaScript off is bad.
They just stop working in Opera users with JS disabled. And not the pages: just the 'jump to top' links. Please :)
13. October 17, 2005 01:22 AM
14. October 17, 2005 06:09 AM
frequency decoder Posted…
Hi guys, I've written a similar script that attaches a 'tweened' scroll mechanism to any link whose href is a fragment identifier.
With JavaScript turned off, the link still works albeit, without the animated scroll. With JavaScript turned on, the page should scroll smoothly to the position of the fragment identifier contained within the href.
This version is a reworking of a script originally provided by squid-fingers:
http://squidfingers.com/code/dhtml/?id=scrollwin
I've just made it unobtrusive and changed the attach method.
A demo can be found on http://www.frequency-decoder.com/ (just click any of the up-arrows to initiate the autoscroll). Those of you interested enough can view the js here (the object fdScroller is what your after):
http://www.frequency-decoder.com/js/fd-generic.js
I quite like Eriks idea of catching the event bubble though!
15. October 17, 2005 05:57 PM
kirkaracha Posted…
I'd recommend saying "Top of page" instead of "Back to top," since they might have gotten to the bottom of the page via an external link, and they might be expecting "back" to mean something other than the top of the page.
16. October 20, 2005 03:44 PM
djQuickTip Posted…
I'd recommend just saying "To Top" instead of "Top of Page". The word "page" is redundant. If not page, where else will you be going to the top of?
17. October 20, 2005 07:05 PM
Andy Posted…
In usability testing we've conducted, people have associated the word 'top' with 'beginning' (as in either the homepage or first page of a section of a website). Our recommendation for the link text is 'Page top'.
Also watch out for #top as a destination anchor name, prefer #pageTop to avoid potential conflicts with de facto standards.
Using JavaScript seems a little heavy handed, instead use server-side includes for top-level and footer navigation (with appropriate destination and source anchors).
For more on anchors, naming, etc. see anchors (Motive Glossary).
18. October 20, 2005 09:21 PM
Nate Posted…
Andy, the usability testing you mention is interesting, "Page top" sounds quite sensible.
I would however argue that server-side includes as a technology is neither related to the functionality described here, nor a replacement for the functionality offered by this Javascript. I'd also suggest that when a very short client-side script degrades properly it's the opposite of "heavy handed".
19. October 21, 2005 09:04 AM
Giorgio Martini Posted…
@nate: The second part of andy's post is just outright spam. ;o)
20. October 25, 2005 01:36 PM
Giordano Posted…
Before doing any of this, you might want to fix the float issues on this site. The "top" of this page, as viewed in IE (!) is pushed down below the end of the right sidebar. The top is not the top. hmm... :>
21. October 25, 2005 01:41 PM
Nate Posted…
Giordano - I can't replicate the problem you're seeing.. what browser version and platform? Also, there are no float issues, because there are no floats! just a whole page margin.
22. October 25, 2005 02:23 PM
Giordano Posted…
I was looking at the page on IE6 / WinXP Home SP2. I'm at dlp at silverthreaded dot com and can send you a screenshot if you email me. Looks fine in Firefox but may be prey to a "box-model" issue in IE, at least from where I'm sitting. Sorry to be off topic... Cheers.
23. November 22, 2005 05:02 PM
Zach Inglis Posted…
As far as I am aware, that's not unobtrusive Javascript.
Unobtrusive Javascript would involve the code <a href="<?=$post_url?>" class='backtotop'>Back to Top</a>
and your javascript would have (onload)
document.getElementByClass('backtotop').onclick="window.scrollTo(0,0); return false"
24. November 22, 2005 07:03 PM
David Lindquist Posted…
Zach, the pedantic nitpickers already beat you to the punch, as can be seen in the first post of this thred. :)
I was using the term "unobtrusive" as an alias for "graceful degradation".
25. December 1, 2005 01:27 AM
Shadoefax Posted…
Firefox users can install a nifty "Back to Top" extension that pretty much eliminates the need for Back to Top links. https://addons.mozilla.org/extensions/moreinfo.php?id=658
26. December 12, 2005 02:59 AM
Joan Posted…
Thank you so much for this tip on Back to the top, I've been going mad editing this site as some pages have no scroll bar and the scrolling is soooo sloooowww...arrggghh!! You have saved my sanity! And most likely anyone visiting my site will thank you too. Thanks again, Joan
27. May 7, 2006 02:57 PM
Mike Hutchinson Posted…
Very nice solution. I was getting a lot of problems with browsers not actually taking me to the real "top", there were always just a couple of scrollable lines left for some reason and your solution cleared the problem.
Opera threw out another problem. I had a javascript link to refresh the page but Opera then scrolls you back to the line you were on after the refresh, even though you clearly see the browser take you to the very top of the page first(!). Your solution came to the rescue with a small modification to include an optional page reload statement. I am therefore using your code to get me to the top of the page and only then issuing the page refresh via javascript. As I am already at the top of the page that is where Opera returns me. Tacky but it works. Thanks again for sharing your very neat bit of code.
Justin Posted…
To be truly unobtrusive you'd scan your page links on page load for ones that just linked to "#" and add the onclick handler then instead of declaring them inline.