Modifying Location.Hash Without Page Scrolling

Modifying location.hash without page scrolling

I think I may have found a fairly simple solution. The problem is that the hash in the URL is also an element on the page that you get scrolled to. if I just prepend some text to the hash, now it no longer references an existing element!

$(function(){
//This emulates a click on the correct button on page load
if(document.location.hash){
$("#buttons li a").removeClass('selected');
s=$(document.location.hash.replace("btn_","")).addClass('selected').attr("href").replace("javascript:","");
eval(s);
}

//Click a button to change the hash
$("#buttons li a").click(function(){
$("#buttons li a").removeClass('selected');
$(this).addClass('selected');
document.location.hash="btn_"+$(this).attr("id")
//return false;
});
});

Now the URL appears as page.aspx#btn_elementID which is not a real ID on the page. I just remove "btn_" and get the actual element ID

Can I update window.location.hash without having the web page scroll?

This behavior is very much possible. You should look into some of the libraries that have been developed to give you this functionality.

Really Simple History: http://code.google.com/p/reallysimplehistory/
SWFAddress: http://www.asual.com/swfaddress/

How to change location.hash without page scroll

While using target selector css will definitely solve this, the following is for situations where you really do need to modify classes or other properties.

You can simplify all the js by using common class names and looping over the elements in a collection and toggling classes based on conditional logic

const items = document.querySelectorAll('.item')

window.addEventListener("hashchange", (e) => {
const id = location.hash.slice(1);
items.forEach(elem => {
const isActive = elem.id === id;
elem.classList.toggle('active', isActive);
});
});
a {
padding: 20px;
margin-right: 5px;
}

.item {
display: none;
}

.item.active {
display: block
}
<a href='#home' class=''>home</a><a href='#projects' class=''>projects</a><a href='#skills' class=''>skills</a><a href='#about' class=''>about</a>

<div id='home' class='item active'>
<p>content home.</p>
</div>
<div id='projects' class="item">
<p>content projects.</p>
</div>
<div id='skills' class="item">
<p>content skills.</p>
</div>
<div id='about' class="item">
<p>content about.</p>
</div>

How can I remove the location hash without causing the page to scroll?

I believe if you just put in a dummy hash it won't scroll as there is no match to scroll to.

<a href="#A4J2S9F7">No jumping</a>

or

<a href="#_">No jumping</a>

"#" by itself is equivalent to "_top" thus causes a scroll to the top of the page

How can I update window.location.hash without jumping the document?

There is a workaround by using the history API on modern browsers with fallback on old ones:

if(history.pushState) {
history.pushState(null, null, '#myhash');
}
else {
location.hash = '#myhash';
}

Credit goes to Lea Verou

Change location.hash without page scrolling

The first line seems wrong:

hash = hash.replace( /^#/, '' );

Are you sure you defined the hash variable before it?

I think it has to be like this:

var hash = document.location.href;
hash = hash.replace( /^#/, '' );

and then the rest of code shouldn't cause the error

Javascript change window.location.hash without scrolling, but still trigger CSS :target pseudo-class

Actually, history.pushState probably should update the CSS :target selector, since using the browser back and forward buttons to navigate back and forward after using history.pushState does indeed update it. It has an open bug in webkit, and there is talk of standardizing the behavior to be one way or the other, rather than the current inconsistent behavior. If they choose to make it update the CSS, then your code will just work as-is. If they choose to make it not update the CSS, then browsers will have to change the behavior of the back and forward buttons to not update the CSS for entries created by history.pushState, or possibly any, which seems like an obviously wrong move.

So, your code may work without changes in the future, but as of right now you have to work around this by calling history.pushState and then navigating back and forward for the user. Here's a solution based on a solution by laughinghan on GitHub:

function pushHashAndFixTargetSelector(hash) {
history.pushState({}, document.title, hash); //called as you would normally
const onpopstate = window.onpopstate; //store the old event handler to restore it later
window.onpopstate = function() { //this will be called when we call history.back()
window.onpopstate = onpopstate; //restore the original handler
history.forward(); //go forward again to update the CSS
};
history.back(); //go back to trigger the above function
}

Theoretically, this workaround will keep working even after they standardize the intended behavior.

add a hash with javascript to url without scrolling page?

Any hash that isn't present on the page should give you this behaviour. For example, this link points to a non-existant hash on this page. (Link tested with Chrome 2.0 and IE 6 (the only browsers I have available to me at the moment).)

So if your URL is causing you to go to the top of the page, make sure you have nothing on the page whose id or name is that address.

window.location.hash = ; prevent scrolling to the top?

There's the onhashchange event, but it cannot be cancelled reliably across browsers to prevent scrolling. The best solution is to record the scroll position before changing the hash location and reset it afterwards. For example, the following code will catch a click on any link ― that doesn't stop propagation ― with a href value of # and prevent the page from scrolling vertically:

document.onclick = function (evt) {
var tgt = (evt && evt.target) || event.srcElement,
scr = document.body.scrollTop;

if (tgt.tagName == "A" && tgt.href.slice(-1) == "#") {
window.location.href = "#";
document.body.scrollTop = scr;
return false;
}
}

If you're changing the hash through script, you can use the following code:

var scr = document.body.scrollTop;
window.location.href = '#';
document.body.scrollTop = scr;

Either of those methods can be adjusted to avoid scrolling individual elements or scrolling the page horizontally. Note that you can remove the entire hash (including the #) without causing navigation or scrolling in modern browsers by calling the pushState or replaceState functions.



Related Topics



Leave a reply



Submit