My site has a fixed navbar which causes problems when using hashes (www.somesite.com/a_page#some_hash) to jump to certain elements on the page. When the page jumps to the hashed element,fixed navbar covers part of the element. I am trying to make it so the page scrolls to element with an offset:
function getHash() {
var hash = window.location.hash;
return hash;
}
$(document).ready(function(){
if (getHash()) {
$(getHash()).fadeOut(300).fadeIn(300)
.fadeOut(300).fadeIn(300)
.fadeOut(300).fadeIn(300);
scrollTo( 0, $(getHash()).offset().top + 200);
}
})
Now, this the scrollTo part is not firing for some reason. The part right above that does (the fadeOut & fadeIn part). When I use the scrollTo line, scrollTo( 0, $(getHash()).offset().top - 200);, in the console, it work just as it should. Why isn't it scrolling when I load the page with a hash in the link? Any and all input is appreciated.
How about a function that overrides the default functionality of any link who's href value begins with a hash tag? Is that something you'd be interested in?
$(document).ready(function() {
$('a[href^="#"]').on('click', function(e) {
// prevent the default behavior so your named anchors don't cause
// a parent with an overflow to 'slide-under' it's parent.
e.preventDefault();
$('html, body').animate({ scrollTop: $($(this).attr('href')).position().top }, 'slow');
});
});
Fiddle proof of concept
Hashes seemed to be causes an immense problem. Especially because a hashed link that refers to the current page does not reload the page. As a result, any new content it not loaded. I just decided to get rid of hashes and use query parameters to simplify all the issues associated with hashes.
My url's now look like this:
www.some_site.com/some_page?element=3434
Then this query to find the element and scroll to it with an offset:
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
$(document).ready(function(){
var post_url_param = getUrlVars()["element"];
var hashed_element_id = '#' + post_url_param;
if (post_url_param) {
$(hashed_post_id).fadeOut(300).fadeIn(300).fadeOut(300).fadeIn(300).fadeOut(300).fadeIn(300);
scrollTo( 0, $(hashed_post_id).offset().top - 250);
}
})
Related
Good evening everybody! Currently, on the site I'm working on (http://bit.ly/1eGCShX), I've got it to scroll down to each div all the way down, however after you've finished and click on the last one again, it doesn't scroll back all the way to the top (instead the previous div) and that's what I'm trying to accomplish.
However, I need it to repeat itself over again to start back from the first div, because if you finish it once and scroll up to click the first one again it stars where it left off. I've been messing with this for awhile and couldn't get it. Any help is kindly appreciated! Here is my JS;
$('div.section').first();
$('a.display').on('click', function(e) {
e.preventDefault();
var t = $(this).text(),
that = $(this);
if ($('.currentPanel').next('div.section').length > 0) {
var $next = $('.currentPanel').next('.section');
var top = $next.offset().top;
$('.currentPanel').removeClass('currentPanel');
$(function () {
$next.addClass('currentPanel');
$('html, body').animate({scrollTop: $('.currentPanel').offset().top }, 'slow');
});
} else if ($('.currentPanel').prev('div.section').length > 0) {
var $prev = $('.currentPanel').prev('.section');
var top = $prev.offset().top;
$('.currentPanel').removeClass('currentPanel');
$(function () {
$prev.addClass('currentPanel');
$('html, body').animate({scrollTop: $('.currentPanel').offset().top }, 'slow');
});of
}
});
And of course, the JSFiddle to make things x10 more easier! I've made a simplified version.
http://jsfiddle.net/dylanopet/ADsKH/9/
Again, appreciate for taking your time to read this and wish you all a positive week.
Where you have
var $prev = $('.currentPanel').prev('.section');
change it to
var $prev = $('.section').eq(0);
You were telling the function you wanted to scroll to the previous element. But you actually want to scroll to the first element.
Working example: http://jsfiddle.net/58ZMZ/
I am wanting to add an offset from the top and smooth scroll to the following function,
The functionality is on one button thats fixed and follows the user down the page. This button has to be able to scroll through numerous anchors and then go back to the first one, with an offset ideally of 105px from the top. trawled the net for hours for help and dont have the jquery know how myself to fix this, any help??
Similar example here - http://www.google.com/nexus/7/ (button in bottom right)
<script>
var max = 6;
function goToNext() {
var hash = String(document.location.hash);
if (hash && hash.indexOf(/anchor/)) {
var newh = Number(hash.replace("#anchor",""));
(newh > max-1) ? newh = 0 : void(null);
document.location.hash = "#anchor" + String(newh+1);
} else {
document.location.hash = "#anchor1";
}
}
</script>
<div id="anchor1"></div>
<div id="anchor2"></div>
<div id="anchor3"></div>
<div id="anchor4"></div>
<div id="anchor5"></div>
<div id="anchor6"></div>
You can make it scroll smoothly to the element using animate({scrollTop:value},delay).
$('document').ready(function () {
//on DOM ready change location.hash to 'anchor1'
window.location.hash = 'anchor1';
//GO TO NEXT click event:
$('a').click(function (e) {
//preventing the default <a> click (href="#")
e.preventDefault();
//get the current hash to determine the current <div> id
var hash = window.location.hash,
//find the (next) immediate following sibling of the current <div>
$next = $(hash).next('div');
//check if this next <div> sibling exist
if ($next.length) {
var id = $next.attr('id'),
nextOffsetTop = $next.offset().top;
//animate scrolling and set the new hash
$('body, html').animate({scrollTop: nextOffsetTop}, 'slow');
window.location.hash = id;
}else{
//else if the next <div> sibling does not exist move to the first anchor
var first = '#anchor1';
$('body, html').animate({scrollTop: $(first).offset().top},'slow');
window.location.hash = first;
}
});
})
See this jsfiddle.
Then comes the flickering. Actually it does not flicker but somewhat jerky, if you look closely into the code above. I am setting the animate(scrollTop) first, then changing the hash window.location.hash = id. Now when the animate starts scrolling and suddenly we are changing the hash it tends to jump directly to the next <div> (this is the default haschange event) but pulled back by the animate() and that causes the scrolling to be jerky.
We cannot just stop the default propagation of the haschange event, there may be a solution to do that but cannot guarantee that it would work on all browsers, each browser has different behaviour when it comes to the haschange event. But thanks to #Andy E solution on that SO post you've provided, we don't need to stop the haschange propagation. We can just simply change the hash first, reset it to last scrollTop() position then animate scrolling at will!
//get the current scrollTop value
var st = $(window).scrollTop();
//change the hash
window.location.hash = id;
//reset the scrollTop
$(window).scrollTop(st);
//animate scrolling
$('body, html').animate({scrollTop: nextOffsetTop}, 'slow');
Check this updated jsfiddle.
Now let's talk about HTML5 History API. The reason I didn't introduced this at first because it is implemented differently across HTML5 (especially IE) browsers and has no fallback for HTML4 browsers, making this method somehow inconsistent. But you can get this done properly using a plugin I guess.
Here's how you can do it using history.pushState():
if ($next.length) {
var id = $next.attr('id'),
nextOffsetTop = $next.offset().top;
history.pushState({state:id}, id, '#'+id);
$('body, html').animate({scrollTop: nextOffsetTop - 105}, 'slow');
}
See this jsfiddle.
That's it. Cheers!
I have an accordion element, and I need to have different panes expand on hashchange. The code I made, expands it but it doesn't scroll the the targeted div, and page never ends loading.
function hashChange() {
if (window.location.hash === '#senior-backend') {
$('#senior-backend, #backend-developer, #senior-frontend, #frontend, #dev-ops').hide(50);
$('#senior-backend').show(50);
$('#job-posts').removeClass().addClass('beige-bg');
$('#job-posts-top').removeClass().addClass('beige-spikes');
}
}
window.onhashchange = hashChange;
Could you please point out what am I doing wrong.
Thanks
You need to scroll the site using animate once you detect a change in the hash, for example:
var dest = $('#yourSelector').position();
var dtop = dest.top;
$('html, body').animate({
scrollTop: dtop
});
Living demo: http://jsfiddle.net/LZbK8/
This is baffling me and I'm afraid I might be doing something very silly.
I have a form that does an ajax call, and on success, reloads the (same) page and jumps to the submitted data toward the bottom of the page using a URL hash/fragments.
window.location.href = "/this/url/#post-10";
window.location.reload();
...
<div id="post-10">...</div>
I notice that at least with Chrome, the previous scroll position is being favored over the anchor link I am providing - so the page reloads, succesfully jumps to my id anchor, but once the page is finished loading, it jumps up to where the scroll was on the previous page.
Is this standard behaviour? Is the best approach to fixing this to simply force the pages position using onLoad or something similar?
window.location.href = "/this/url/#post-10"; will work on its own, there's no need to reload the page a second time, which will (to the best of my knowledge) favor the previous scroll position.
If you are using ajax, why reloading the page ?
Just remove the line window.location.reload();
window.location.href = "/this/url/#post-10"; is sufficient to take the scroll to that post-10 portion.
Btw, a better (cool) approach would be to use a scroll effect.
var targetOffset = $('#post-10').offset().top ;
var scrollElem = scrollableElement('html', 'body');
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
// scroll is complete
location.hash = 'post-10';
});
// Use the first element that is "scrollable" (cross-browser fix?)
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
I basically have a div with set dimensions and overflow: hidden. That div contains 7 child divs (but only shows one at a time) that I would like to be smoothly scrolled through vertically when their respective links are hovered.
However, the first section (div) doesn't have a link and is the default section when no link is hovered.
Take a look at this jsFiddle to see a basic structure of what I'm talking about: http://jsfiddle.net/YWnzc/
I've attempted to accomplish this with jQuery scrollTo but haven't been able to get it to work.
Any help would be greatly appreciated. Thanks.
Something like this?
http://jsfiddle.net/YWnzc/5/
code:
jQuery("#nav").delegate("a", "mouseenter mouseleave", function (e) {
var i, self = this,
pos;
if (e.type == "mouseleave") {
i = 0;
}
else {
//Find out the index of the a that was hovered
jQuery("#nav a").each(function (index) {
if (self === this) {
i = index + 1; //the scrollTop is just calculated from this by a multiplier, so increment
return false;
}
});
}
//Find out if the index is a valid number, could be left undefined
if (i >= 0) {
//stop the previous animation, otherwise it will be queued
jQuery("#wrapper").stop().animate({
scrollTop: i * 200
}, 500);
//I would retrieve .offsetTop, but it was reporting false values :/
}
e.preventDefault();
});
FYI : That JSFIDDLE you sent me to went to MooTools framework, not jQuery... fyi. (might be why its not working?
Copy and paste this code exactly and it will work in jQuery for animated scrolling.
Try this for smooth scrolling within the DIV, I tested it - it works great. You
$(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('#wrapper');
// Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
$('a[href*=#]').each(function() {
// Ensure it's a same-page link
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
// Ensure target exists
var $target = $(this.hash), target = this.hash;
if (target) {
// Find location of target
var targetOffset = $target.offset().top;
$(this).click(function(event) {
// Prevent jump-down
event.preventDefault();
// Animate to target
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
// Set hash in URL after animation successful
location.hash = target;
});
});
}
}
});
// Use the first element that is "scrollable" (cross-browser fix?)
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
});
FYI : Credit for this code does not go to me as an individual developer, although I did slightly tweak the code. The owner and creator of this code is Chris Coyier and you can find more about this scrolling code here:
http://css-tricks.com/snippets/jquery/smooth-scrolling/
Here's a working example: http://jsfiddle.net/YWnzc/7/
And the code (pretty similar to rizzle's, with a couple changes that I'll explain):
$('a').hover(function(){
var selector = $(this).data('section');
var scrollAmount = $(selector).offset().top + $('#wrapper')[0].scrollTop - 129;
$('#wrapper').animate({scrollTop: scrollAmount}, 250);
},function(){
$('#wrapper').animate({scrollTop: 0}, 250);
});
First, var selector = $(this).data('section'); because in jsFiddle, the href attribute was returning the full path of the page + the hash. So I changed it to an html5 data attribute (data-section).
The next line is similar to rizzle's, except that we grab the offset of the section and add it to the current scrollTop value of the #wrapper. As he pointed out, there are some weird offset issues going on still, and I found that subtracting 129 did the trick. While this 129 number might seem like something that is likely to break, I did test out changing the sizes of the sections, making them not equal, etc, and it continued to work. I'm using Chrome, and perhaps a non-webkit browser would need a different constant to subtract. But it does seem like that 129 number is at least some kind of constant.
The rest should be pretty self-explanatory.
One thing to note: as you move your cursor over the <a> tags, the content of the #wrapper div will seem to jump around, but that's just because the mouseleave part of the hover event briefly gets triggered as the cursor moves. I'm sure you can solve that one though :)
$("#nav a").hover(function () {
var sectionName = $(this).attr("href");
var sectionPos = $(sectionName).offset().top;
var wrapperPos = $("#wrapper").offset().top;
var wrapperScroll = $("#wrapper").scrollTop();
var scrollPos = sectionPos - wrapperPos + wrapperScroll;
$("#wrapper").stop().animate({scrollTop:scrollPos}, 600);
}, function () { $("#wrapper").stop().animate({scrollTop:0}, 600); });