How do I stop a web page from scrolling to the top when a link is clicked that triggers JavaScript?
Asked Answered
C

16

169

When I have a link that is wired-up with a jQuery or JavaScript event such as:

<a href="#">My Link</a>

How do I prevent the page from scrolling to the top? When I remove the href attribute from the anchor the page doesn't scroll to the top but the link doesn't appear to be click-able.

Capuchin answered 21/10, 2009 at 16:20 Comment(0)
I
230

You need to prevent the default action for the click event (i.e. navigating to the link target) from occurring.

There are two ways to do this.

Option 1: event.preventDefault()

Call the .preventDefault() method of the event object passed to your handler. If you're using jQuery to bind your handlers, that event will be an instance of jQuery.Event and it will be the jQuery version of .preventDefault(). If you're using addEventListener to bind your handlers, it will be an Event and the raw DOM version of .preventDefault(). Either way will do what you need.

Examples:

$('#ma_link').click(function($e) {
    $e.preventDefault();
    doSomething();
});

document.getElementById('#ma_link').addEventListener('click', function (e) {
    e.preventDefault();
    doSomething();
})

Option 2: return false;

In jQuery:

Returning false from an event handler will automatically call event.stopPropagation() and event.preventDefault()

So, with jQuery, you can alternatively use this approach to prevent the default link behaviour:

$('#ma_link').click(function(e) {
     doSomething();
     return false;
});

If you're using raw DOM events, this will also work on modern browsers, since the HTML 5 spec dictates this behaviour. However, older versions of the spec did not, so if you need maximum compatibility with older browsers, you should call .preventDefault() explicitly. See event.preventDefault() vs. return false (no jQuery) for the spec detail.

Intentional answered 21/10, 2009 at 16:21 Comment(3)
Posted a solution (3 years late) that doesn't require attaching a click handler: https://mcmap.net/q/143296/-how-do-i-stop-a-web-page-from-scrolling-to-the-top-when-a-link-is-clicked-that-triggers-javascriptPaly
In this case, Achilles is just doing this because he wants the link to appear as clickable, for which he doesnt need to use href="#" at all. See my answer for more info.Brae
Good add to this solution @achecopar, the "#!" add for executing functions using onclick prevents the scroll behavior.Reel
P
206

You can set your href to #! instead of #

For example,

<a href="#!">Link</a>

will not do any scrolling when clicked.

Beware! This will still add an entry to the browser's history when clicked, meaning that after clicking your link, the user's back button will not take them to the page they were previously on. For this reason, it's probably better to use the .preventDefault() approach, or to use both in combination.

Here is a Fiddle illustrating this (just scrunch your browser down until your get a scrollbar):
http://jsfiddle.net/9dEG7/


For the spec nerds - why this works:

This behaviour is specified in the HTML5 spec under the Navigating to a fragment identifier section. The reason that a link with a href of "#" causes the document to scroll to the top is that this behaviour is explicitly specified as the way to handle an empty fragment identifier:

2. If fragid is the empty string, then the indicated part of the document is the top of the document

Using a href of "#!" instead works simply because it avoids this rule. There's nothing magic about the exclamation mark - it just makes a convenient fragment identifier because it's noticeably different to a typical fragid and unlikely to ever match the id or name of an element on your page. Indeed, we could put almost anything after the hash; the only fragids that won't suffice are the empty string, the word 'top', or strings that match name or id attributes of elements on the page.

More exactly, we just need a fragment identifier that will cause us to fall through to step 8 in the following algorithm for determining the indicated part of the document from the fragid:

  1. Apply the URL parser algorithm to the URL, and let fragid be the fragment component of the resulting parsed URL.

  2. If fragid is the empty string, then the indicated part of the document is the top of the document; stop the algorithm here.

  3. Let fragid bytes be the result of percent-decoding fragid.

  4. Let decoded fragid be the result of applying the UTF-8 decoder algorithm to fragid bytes. If the UTF-8 decoder emits a decoder error, abort the decoder and instead jump to the step labeled no decoded fragid.

  5. If there is an element in the DOM that has an ID exactly equal to decoded fragid, then the first such element in tree order is the indicated part of the document; stop the algorithm here.

  6. No decoded fragid: If there is an a element in the DOM that has a name attribute whose value is exactly equal to fragid (not decoded fragid), then the first such element in tree order is the indicated part of the document; stop the algorithm here.

  7. If fragid is an ASCII case-insensitive match for the string top, then the indicated part of the document is the top of the document; stop the algorithm here.

  8. Otherwise, there is no indicated part of the document.

As long as we hit step 8 and there is no indicated part of the document, the following rule comes into play:

If there is no indicated part ... then the user agent must do nothing.

which is why the browser doesn't scroll.

Paly answered 28/6, 2012 at 13:49 Comment(3)
Doesn't matter if you put '!' or any other value, as long as the id is not a part of the DOM.Kylander
After once being an advocate of this method, I've since done a 180 and advise against it. Beware: links like this will still change the page URL, resulting in an extra entry in the browser's history and causing the "back" button to simply remove the fragment from the URL instead of doing what the user expects. Thus this solution on its own, while answering the question as asked, typically isn't a desirable alternative to using preventDefault() in a click handler - rather sadly.Attitudinize
Why not using href="javascript:;" instead? As far as I know it won't change the browser's history. Posted about it on my answer.Brae
P
40

An easy approach is to leverage this code:

<a href="javascript:void(0);">Link Title</a>

This approach doesn't force a page refresh, so the scrollbar stays in place. Also, it allows you to programmatically change the onclick event and handle client side event binding using jQuery.

For these reasons, the above solution is better than:

<a href="javascript:myClickHandler();">Link Title</a>
<a href="#" onclick="myClickHandler(); return false;">Link Title</a>

where the last solution will avoid the scroll-jump issue if and only if the myClickHandler method doesn't fail.

Pelagia answered 21/10, 2009 at 18:27 Comment(0)
B
19

You should change the

<a href="#">My Link</a>

to

<a href="javascript:;">My Link</a>

This way when the link is clicked the page won't scroll to top. This is cleaner than using href="#" and then preventing the default event from running.

I have good reasons for this on the first answer to this question, like the return false; will not execute if the called function throws an error, or you may add the return false; to a doSomething() function and then forget to use return doSomething();

Brae answered 14/6, 2017 at 15:38 Comment(1)
Thanks! Worked exactly as I expected.Hartle
E
13

Returning false from the code you're calling will work and in a number of circumstances is the preferred method but you can also so this

<a href="javascript:;">Link Title</a>

When it comes to SEO it really depends on what your link is going to be used for. If you are going to actually use it to link to some other content then I would agree ideally you would want something meaningful here but if you are using the link for functionality purposes maybe like Stack Overflow does for the post toolbar (bold, italic, hyperlink, etc) then it probably doesn't matter.

Echovirus answered 21/10, 2009 at 17:24 Comment(0)
M
8

Try this:

<a href="#" onclick="return false;">My Link</a>
Monody answered 21/10, 2009 at 16:22 Comment(0)
A
8

If you can simply change the href value, you should use:

<a href="javascript:void(0);">Link Title</a>

Another neat solution I just came up with is to use jQuery to stop the click action from occurring and causing the page to scroll, but only for href="#" links.

<script type="text/javascript">
    /* Stop page jumping when links are pressed */
    $('a[href="#"]').live("click", function(e) {
         return false; // prevent default click action from happening!
         e.preventDefault(); // same thing as above
    });
</script>
Aframe answered 16/3, 2012 at 1:51 Comment(1)
Surely the return false should be after the preventDefault() line, otherwise you'll never get to this second line?Curcio
F
5

Link to something more sensible than the top of the page in the first place. Then cancel the default event.

See rule 2 of pragmatic progressive enhancement.

Fasciculus answered 21/10, 2009 at 16:40 Comment(1)
This also makes you site more SEO friendly.Orthodontist
A
3

Also, you can use event.preventDefault inside onclick attribute.

<a href="#" onclick="event.preventDefault(); doSmth();">doSmth</a>

No need to write exstra click event.

Adumbral answered 16/12, 2016 at 15:26 Comment(0)
M
3

event.preventDefault() will stop the scrolling but also not change the link state to visited (color), which I need. The "3 years late" solution is not too late and eliminates unforseen side-effects. The hrefs I create are in a loop (indexed by "i") "#i!", where i is the index to an array containing the text for the anchor tag. Works like a charm. (Just #i would work too, except I have other ids set to i).

While I'd like to use the `href='javascript:function()'` approach, this adds 11 bytes (javascript:) plus the bytes of the function name plus parameters to the page size. Mutiply this by 1000+ hrefs and thats 16kb+ added to the page size. (Yes, pagination would help but not for the user). So maybe in a different situation I'd go with the javascript: solution.

Morville answered 13/7, 2022 at 19:34 Comment(0)
R
2

For Bootstrap 3 for collapse, if you don't specify data-target on the anchor and rely on href to determine the target, the event will be prevented. If you use data-target you'll need to prevent the event yourself.

<button type="button" class="btn btn-default" data-toggle="collapse" data-target="#demo">Collapse This</button>

<div id="demo" class="collapse"> 
<p>Lorem ipsum dolor sit amet</p>
</div>
Reinforce answered 8/4, 2018 at 18:54 Comment(0)
V
1

You can simply write like this also:-

<a href="#!" onclick="function()">Delete User</a>
Vedda answered 31/5, 2013 at 16:33 Comment(0)
K
1

When calling the function, follow it by return false example:

<input  type="submit" value="Add" onclick="addNewPayment();return false;">
Kurman answered 3/9, 2014 at 17:45 Comment(0)
E
1

Create a page which contains two links- one at the top and one at the bottom. On clicking the top link, the page has to scroll down to the bottom of the page where bottom link is present. On clicking the bottom link, the page has to scroll up to the top of the page.

Ednaedny answered 6/8, 2016 at 8:34 Comment(0)
R
1
<a onclick="yourfunction()">

this will work fine . no need to add href="#"

Rink answered 11/1, 2017 at 9:51 Comment(0)
M
1

You might want to check your CSS. In the example here: https://css-tricks.com/the-checkbox-hack/ there's position: absolute; top: -9999px;. This is particularly goofy on Chrome, as onclick="whatever" still jumps to the absolute position of the clicked element.

Removing position: absolute; top: -9999px;, for display: none; might help.

Megohm answered 6/6, 2017 at 16:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.