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
How to Open an External Link in Safari Not the App's Uiwebview
Is There an Alternative Method to Use Onbeforeunload in Mobile Safari
Resize Cross Domain Iframe Height
How to Raw Url Encode/Decode in JavaScript and Ruby to Get the Same Values in Both
Escaping </Script> Tag Inside JavaScript
How to Use CSSstylesheet.Insertrule() Properly
How to Check Element's Visibility via JavaScript
Jquery - How to Disable the Entire Page
How to Set the Universal CSS Selector with JavaScript
IE8 V8 Not Changing Class for a Dom Element Despite Js Function Changing the Element Attribute
How to Prevent Pull-Down-To-Refresh of Mobile Chrome
Jquery Mobile Prevent Scroll-To-Top Before Page Transition