5

Sorry for the ugly layout example below... http://www.wthdesign.net/test/test2.html

I managed to append my id name to the url:

function generateUrl(el)
{
    var currentId = $(el).attr('id');
    document.location.hash = currentId;
}

and add:

<a id="abc2" onClick="generateUrl(this)" >this is an anchor btn</a>

but this end up having the same effect as:

<a id="abc2" href="#abc2" >this is an anchor btn</a>

Everything is fine but I just don't want it to scroll when when I click on the link How should I do that? Many thanks in advance.

m59
  • 43,214
  • 14
  • 119
  • 136
Vincent Chua
  • 969
  • 6
  • 20
  • 41
  • `location` is not part of `document` but `window`; also `location.hash = el.id;` would be enough in your function. In any case, you're changing the location hash to `#abc2`, so why shouldn't it scroll there? – Ja͢ck Apr 09 '13 at 03:47
  • Look here: http://stackoverflow.com/questions/1489624/modifying-document-location-hash-without-page-scrolling – Krets Apr 09 '13 at 03:53
  • Actually I'm using an javascript accordion plugin in the website but the problem is that the accordion will not append the url when the button is click.... The reason why I do not want to included the scroll is because it will mess up the accordion scrolling.... – Vincent Chua Apr 09 '13 at 03:54
  • @Jack https://developer.mozilla.org/en-US/docs/DOM/document.location – Ian Apr 09 '13 at 03:59
  • @VincentChua https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#Adding_and_modifying_history_entries – Ian Apr 09 '13 at 04:03
  • @Jack That's different than saying "`location` is not part of `document` but `window`" – Ian Apr 09 '13 at 04:06
  • @Jack I'm not trying to argue it. I'm just saying it would be more helpful to say "while `document.location` is valid, it's preferred to use `window.location` for security reasons and cross browser compatibility". It amazes me to see how many questions/answer on here use `document.location`, and no one says anything. (I agree `window.location` should be used, I'm just saying) – Ian Apr 09 '13 at 04:10
  • Did my answer not work out for you? No vote, no accept, and no comment? – m59 Feb 27 '14 at 07:14

3 Answers3

12

If the ids aren't necessary, just an href="#some-value will change the window location without scrolling the page. If you do need the id in the document (on the a tags in this case) then the location change will cause a scroll. You can work around this by using the history object in modern browsers or by storing the scroll location on the link click, then resetting it using the hashchange event.

I will use this markup for both solutions:

Sample markup:

<div class="filler"></div>
<a id="abc1" href="#abc1" class="my-class">this is an anchor btn</a>
<div class="filler"></div>
<a id="abc2" href="#abc2" class="my-class">this is an anchor btn</a>
<div class="filler"></div>
<a id="abc3" href="#abc3" class="my-class">this is an anchor btn</a>
<div class="filler"></div>

history.replaceState or history.pushState

Live demo (click).

//get element referneces
var elems = document.getElementsByClassName('my-class');

//iterate over the references
for (var i=0; i<elems.length; ++i) {
  //add click function to each element
  elems[i].addEventListener('click', clickFunc);
}

//this will store the scroll position
var keepScroll = false;

//fires when a ".my-class" link is clicked
function clickFunc(e) {
  //prevent default behavior of the link
  e.preventDefault();
  //add hash
  history.replaceState({}, '', e.target.href);
}

scrollTop and hashchange event

Live demo (click).

JavaScript:

//get element referneces
var elems = document.getElementsByClassName('my-class');

//iterate over the references
for (var i=0; i<elems.length; ++i) {
  //add click function to each element
  elems[i].addEventListener('click', clickFunc);
}

//this will store the scroll position
var keepScroll = false;

//fires when a ".my-class" link is clicked
function clickFunc(e) {
  //if the location hash is already set to this link
  if (window.location.hash === '#'+e.target.id) {
    //do nothing
    e.preventDefault(); 
  }
  else {
    //the location will change - so store the scroll position
    keepScroll = document.body.scrollTop;
  }
}

window.addEventListener('hashchange', function(e) {
  //the location has has changed

  //if "keepScroll has been set
  if (keepScroll !== false) {
    //move scroll position to stored position
    document.body.scrollTop = keepScroll;
    //set "keepScroll" to false so that this behavior won't affect irrelevant links
    keepScroll = false;
  }
});
m59
  • 43,214
  • 14
  • 119
  • 136
2

I had the problem that I use the smooth scroll behaviour and firefox scroll position jumps around while clicking anchor links. So nothing here on stack overflow worked out well. If anyone is interested in my recent approach:

  1. Store current scroll position in a scroll listener
  2. Create a hashchange listener
  3. Prevent scrolling by adding css to body, make use of the window.scroll function and immediately remove css from body to enable scrolling

Here is an example:

document.addEventListener('DOMContentLoaded', () => {

  // store scroll position
  let scrollTop = document.documentElement.scrollTop
  window.addEventListener('scroll', () => scrollTop = document.documentElement.scrollTop)

  window.addEventListener('hashchange', () => {
    // disable scrolling
    document.body.style.overflow = 'hidden'

    // set current scroll position
    window.scroll(0, scrollTop)

    // enable scrolling
    setTimeout(() => {
      document.body.style.overflow = 'auto'
    }, 10)
  }, false)

  // trigger hashchange event on page load
  window.dispatchEvent(new Event('hashchange'))
})
0

if location.hash = "#" or "" scroll effect appears, in other cases, for example "#anychars" browser chrome

html with scrollbar, long text:

<a href="#c1">c1</a>
<a href="#c2">c2</a>

js:

window.onhashchange=(e) => {
    if (location.hash=='#c1'){
        console.log(1) )
    }
    if (location.hash=='#c2'){
        console.log(2) )
    }
    location.hash="#null"
}