Load different page and then smooth scroll within different page
karland opened this issue ยท 11 comments
Hi, thanks for jquery-smooth-scroll. I think it is excellent.
I would like the smooth scrolling to take place on a different page. So my element on different-page.html
looks like
<a href="/index.html#to-chapter1"> To Chapter 1</a>
I thought I can use the beforeScroll
-function.
// smooth-scroll
$('a[href*=#]:not([href=#])').click(function() {
$.smoothScroll({
beforeScroll: function () {location.replace("/index.html");},
offset: -120,
scrollTarget: this.hash
});
return false;
});
However, smooth-scroll
does not wait for the beforeScroll
-function to be completed, i.e. the page to be loaded. Is there a way to make this happen? Thanks
Hi, I did something like this and here are a couple of tips I can pass on.
Firstly, to prevent the browser from jumping straight to the target when the page loads you can add a suffix to all the scroll target ids, this stops them from immediately matching up with the hash from the address bar. So the target of page.html#target
gets an id of target_hash
rather than just target
. Later some JS adds the suffix to the scrollTarget
before triggering smoothScroll
.
Secondly, I read that for browser compatibility reasons it's worth putting in a short delay before testing the window.location for hash. And it's also worth putting a short delay before executing the smoothScroll function. I don't remember where I read this but the idea is to ensures the page is sufficiently loaded before executing the smoothScroll.
Putting that all together you end up with some code like this. It works for me on a number of sites.
// Requires SmoothScroll and jQuery
$(document).ready(function() {
/* Take over default page anchor functionality */
// Store hash location
var hashLocation = false;
if (location.hash) {
hashLocation = window.location.hash;
setTimeout(function() {
hashLocation = window.location.hash;
}, 1); // Execute at two moments for browser compatibility reasons
}
// If we have a hash location do stuff
if (hashLocation) {
// delay .1s for browser compatibility reasons
setTimeout(function() {
// Check hashLocation suffix
if( hashLocation.indexOf('_hash') < 0 ) {
hashLocation = hashLocation + "_hash";
};
// Scroll to target
$.smoothScroll({
scrollTarget: hashLocation
});
}, 100);
};
});
@LL782 thanks a lot. It helped me to find the solution below together with two other sources: 1 and 2.
My final solution looks like that (tested under IE11, Firefox, Chrome, Opera, Safari):
$(document).ready(function() {
var scrollnow = function(e) {
// if scrollnow()-function was triggered by an event
if (e) {
e.preventDefault();
var target = this.hash;
}
// else it was called when page with a #hash was loaded
else {
var target = location.hash;
}
// same page scroll
$.smoothScroll({
offset: -120,
scrollTarget: target
});
};
// if page has a #hash
if (location.hash) {
$('html, body').scrollTop(0).show();
// smooth-scroll to hash
scrollnow();
}
// for each <a>-element that contains a "/" and a "#"
$('a[href*="/"][href*=#]').each(function(){
// if the pathname of the href references the same page
if (this.pathname.replace(/^\//,'') == location.pathname.replace(/^\//,'') && this.hostname == location.hostname) {
// only keep the hash, i.e. do not keep the pathname
$(this).attr("href", this.hash);
}
});
// select all href-elements that start with #
// including the ones that were stripped by their pathname just above
$('a[href^=#]:not([href=#])').click(scrollnow);
});
@karland : you can change the .each()
loop to a .filter()
function and call .click()
on the filtered links:
// for each <a>-element that contains a "/" and a "#"
$('a[href*="/"][href*=#]').filter(function(){
// if the pathname of the href references the same page
return this.hash &&
this.pathname.replace(/^\//,'') == location.pathname.replace(/^\//,'') &&
this.hostname == location.hostname;
}).click(scrollnow);
I should have mentioned that a link like <a href="#">
(as opposed to <a href="#foo">
) does not have a "hash," so this.hash
would equal "".
@kswedberg Thanks a lot. I agree, your code is more elegant. However, I was not very clear of what I wanted to achieve: smooth-scroll for same page AND different page links. The only solution I was able to come up with is the following:
- For "same page links", that contain a path, I have to remove the path first and then bind scrollnow (wrapping smooth-scroll) to all "same page links".
- For all "different page links" I have to leave them as they are and smooth-scroll to the #hash tag, once a page is loaded.
The "problem" with my solution is that I am touching some <a>
-elements twice, which I do not like so much, even if it works ...
@Naren-hybreeder , try putting quotes around the hash:
$('a[href*="/"][href*="#"]')
//โฆ
@kswedberg Thanks for the reply, I tried, My above issue got resolved but when I click on anchor tag then I am getting error in the console.
$.smoothScroll is not a function
I tried the below code which is working for me. I tried below code from one page to anoter page and it's working perfeclty but this code is not working on the same page.
$(document).ready(function() {
$('html, body').hide();
if (window.location.hash) {
setTimeout(function() {
$('html, body').scrollTop(0).show();
$('html, body').animate({
scrollTop: $(window.location.hash).offset().top-100
}, 1000)
}, 0);
}
else {
$('html, body').show();
}
});
@Naren-hybreeder - maybe try noConflict solution? I usually experience this issue if I'm trying to minimize, defer, or Async JS files.
@Naren-hybreeder , it's hard to troubleshoot without seeing what you're doing, but @dpanfili could be right. You might have more than one instance of jQuery loading on the page. Or, you're calling $.smoothScroll
before the smooth scroll plugin has been loaded and parsed.