I replaced the scrolling animation of my one page website with another scrolling animation which changes the URLs when you use the topbar (it was build in foundation)
While the URLs now change when I click an item in the topbar all the other links or clickable elements on my page make it scroll back to the top of the page.
For example when I try to click the next/prev buttons of my slider it scrolls back to the top of the page as if I clicked on Home.
Can someone see whats wrong with the code for the animation?
$(document).ready(function () {
$('a[href^="#"]').click(function () {
var target = $(this.hash),
hash = this.hash;
if (target.length == 0) {
target = $('a[name="' + this.hash.substr(1) + '"]');
}
if (target.length == 0) {
target = $('html');
}
$('html, body').animate({
scrollTop: target.offset().top
}, 500, function () {
location.hash = hash;
});
return false;
});
});
PS: When I scroll manually the URLs don't change when I go down to the next page. If anyone has a fix for this I'll be happy to here from you! (I tried using history.js but that only seems to work if you have a server, which I don't)
//* EDIT *//
I just found out it's not all links that make it scroll to the top of the page, just the buttons of my orbit slider and the menu button when the topbar is collapsed
//EDIT 2//
The URL now changes when I scroll to the next page!
The only problem I am seeing right now is that the buttons of my orbit slider and the menu button of the collapsed topbar act the same as my home button (makes the page scroll all the way back to the top) for some reason.
So the last thing I need to do is get the buttons working again. Making the menu button expand the topbar and making the next and prev buttons of my slider work as normal
If you only want to change the hash depending on the scrollPosition you are half way there.
You'll need to bind some logic to the scroll event. Here is a fork of your Fiddle where the hash is changed on scroll.
When the user scrolls the page we iterate through all .page elements and compare their offset().top against $( document ).scrollTop().
We set the new hash to be the id of the last .page element that has a lower offset().top than $( document ).scrollTop() is.
(I also debounced the function so it doesn't fire constantly when scrolling - you could of course remove that part)
You should however consider that by changing the hash you will jump to the equivalent element. Here is a guide on how to suppress that behaviour.
EDIT:
Here is an updated Fiddle where I implemented the solution from above for suppressing forced scroll on hash change.
Related
I have a question, I would like to trigger a specific event in javascript or jquery on a webpage. The page has an animation effect during page loads (the screen and content splits in two and slides open revealing the next content). This works fine when the content on the page fits and doesn't need to be scrolled. However when content needs to be scrolled, the effect doesn't look as good. Is there anyway to trigger an href to scroll back to the top of the page and THEN load the href link/target? In basic terms something like "on click scroll to top and then load link" Any help would be great! Thanks
One could use jquerys animate to scroll to the top, then if that finished redirect:
$("a").click(function() {
$("html, body").animate({ scrollTop: 0 }, "slow", ()=> location.href = this.href );
return false;
});
try it
For some reason my page 'jumps' instead of smoothly scrolling after clicking an internal link in menu 2nd time.
I'm quite sure that has something to do with scrolling.js file, i'm a newbie in jQuery and probably messed something up. Since you've commented that it's working just fine let me explain it on example. I enter the page I can press "About" button in menu and it scrolls just fine, I can press the "Learn About Me" button and it works fine as well, go to top arrow on the side menu works too but if you scroll manually a bit and then try to press "About" in menu it doesn't scroll but jump even if you scroll back to top and press it the same way it worked after the page load.
the page itself.
scrolling.js
$(window).scroll(function(){
var height = $('section').height();
height = height * 0.2;
if ($(window).scrollTop() >= height) {
$('nav').css('background','rgba(0,0,0,0)');
$('nav').css('margin-left','0px');
$('.OTOCWEL').css('background','rgba(0,0,0,0)');
$('#powered').css('background','rgba(0,0,0,0)').addClass('fixerpowered');
$('.menu').addClass('menuslim');
$('.menu').removeClass('menu');
$('.menuslim').css('margin-left','0px').css('opacity','1');
$('#first').addClass('mega-octicon octicon-info').css('margin-left','0px');
$('#second').addClass('mega-octicon octicon-book');
$('#third').addClass('mega-octicon octicon-mail');
$('#fourth').addClass('mega-octicon octicon-diff-added');
$('.OTOCWEL').css('display','none');
$('.suwak').css('display','none');
$('.dzolero').css('display','block');
} else {
$('nav').css('background','rgba(0,0,0,0.5)');
$('.menuslim').addClass('menu');
$('.menu').removeClass('menuslim').css('top','0px');
$('#first').html("<a>About</a>").css('margin- left','15px').removeClass('mega-octicon octicon-info');
$('#first>a').attr('href','#about');
$('#second').html("<a>Projects</a>").removeClass('mega-octicon octicon-book');
$('#second>a').attr('href','#projects');
$('#third').html("<a>Contact</a>").removeClass('mega-octicon octicon-mail');
$('#third>a').attr('href','#contact');
$('#fourth').html("<a>Additional</a>").removeClass('mega-octicon octicon-diff-added');
$('#fourth>a').attr('href','#additional');
$('.OTOCWEL').css('display','initial');
$('.suwak').css('display','block');
$('#powered').removeClass('fixerpowered');
$('.dzolero').css('display','none');
}
});
scroll.js
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
I suspect your JQuery selector $('a[href*=#]:not([href=#])') is the source of the problem.
When it comes to your anchor links (the ones that do not redirect to a new page), you should make it such that all of them enable smooth scrolling.
Think about it, what is the main purpose of your anchor tags? It refers to a document address. The user mainly experiences:
Redirect to a new site.
Navigate through the current site.
Download request of a file.
Therefore, as long as your smooth scroll behavior is specific to all anchors; then you do not need to account for specific anchor behavior. Why? Because you do not care if the anchor redirects/download, smooth scroll should not trigger since the page does not move at all.
TLDR:
Try changing your JQuery selector from:
$('a[href*=#]:not([href=#])').click(function() { //...
To:
$('a').click(function() { //...
Do some unit testing for all scenarios. If that does not solve your problem, then we need to identify what other JavaScript is affecting your smooth scroll.
Thanks for the answer and the kudos for ideas :). I managed to change the selector so it affects all the anchor links not just the internal ones yet it didn't solve the problem. I've tried to test it with another menu section yet the result is the same. It's jumping to "Projects" section instead of smoothly scrolling. I also added instrumental button with anchor link to "Projects" section to see if it's a problem with scrolling script but it worked like a charm. Seems to me like it's a problem with menu script (scrolling.js) rather then with scroll.js
EDIT: The scrolling.js is deleting anchor links when the menu reaches 20% of section height then it rewrites them as menu goes vertical version. Is it possible that the scroll.js script is losing the focus on links as it doesn't scan the document all the time? And so is it possible to make the script rescan the document?
EDIT2: I've managed to fix it by removing the .html() function from scrolling.js
I have a container (div) on the page. This container has a scrolling (provided by overflow:auto; height:400px).
I need no provide a URL, that will open a page so that the main page will not be scrolled, but the text in the container will be scrolled.
I tried www.mysite.com#position, but by this way the main page is scrolled too (and I need, that users will see the header on the top of the screen, and the "#position" position on the top of the container)
This is possible with javascript. And I will show a jQuery example here.
if (window.location.hash == '#position') {
$('#containerDiv').animate({
scrollTop: $("#actual_position").offset().top
}, 2000);
}
The actual_position should be the place where to scroll to. position should just be in the url and not on the page, to prevent the whole page from scrolling.
May you use the css-properties: position:fixed, top:..., left:... for your element that should stay at a certain place on your side, when an user scrolls.
Furthermore you can put all content that you do not want to be scrolled into a div and define the css-properties.
I hope this helps you a little bit.
Really it's an upgrading of Arjan answer (and now this really works).
As Arjan's suggestion the script will not work every time, but only by providing #scroll in the end of url (www.mysite.com#scroll). This script will scroll the container scroll bar to the #position element, and the all document will stay.
jQuery(window).load(function(){
container_top = jQuery('#container').offset().top;
element_top = jQuery('#position').offset().top;
element_relative_top = element_top -container_top;
if (window.location.hash == '#scroll') {
jQuery('#container').animate({
scrollTop: element_relative_top
}, 2000);
}
})
Here is a link to the item in question:
http://www.nychukdesign.com/uploads/dynamic-top-bar-nav-menu.html
All HTML, Javascript and CSS is in the one html file
Functionality description:
This is a simple dynamic horizontal navigation bar that is intended to disappear when a user scrolls down the page, in which a trigger is activated when the user mouses into the area, of which it slides down and reappears, and disappears once more upon mousing out. When the user scrolls back to the top the navigation returns to it's default (static) state...which is where the problem comes in.
Problem description:
Sometimes (and yes I can not re-create this problem every time) when you return to the top of the page, and the navigation returns to it's default state, when the mouse leaves this area (without scrolling down again) the navigation will slide up and disappear. Sometime it will happen on the first try, sometimes after several, and primarily in Firefox 2.0, although I have had it happen once or twice in Safari.
My thoughts:
I am baffled by this, and why I am seeking help. Any advice would be greatly appreciated.
To re-create the problem
Update: I just discovered how to re-create the problem. You must scroll down and trigger the menu at least once, before scrolling back to the top, in which mousing over the menu will for some reason make it disappear.
Code:
<script type="text/javascript">
// Use short notation of DOM ready
$(function(){
// Assign variables for the menu, the trigger and the menu position (relative to the document)
var menu = $('#menu'),
menuTrigger = $('#menu-trigger'),
pos = menu.offset();
// Listen for the scroll event
$(window).scroll(function(){
// If we scroll past the position of the menu's height and it has it's default style, then hide menu.
if($(this).scrollTop() > pos.top+menu.height() && menu.hasClass('default')){
menu.fadeOut('fast', function(){
// Remove the default class and replace with fixed class
$(this).removeClass('default').addClass('fixed');
});
// Initiate the trigger to show and hide the menu with the mouse event
$(menuTrigger).removeClass('hidden').addClass('block').mouseenter(function(){
$(menu).slideDown('fast').mouseleave(function(){
$(menu).slideUp('fast');
});
});
// If we scroll back to top and menu has fixed class, fadeIn menu
} else if($(this).scrollTop() <= pos.top && menu.hasClass('fixed')){
menu.fadeIn('fast', function(){
// Hide the trigger
$(menuTrigger).removeClass('block').addClass('hidden');
// Give menu default style
$(this).removeClass('fixed').addClass('default');
});
}
});
});
</script>
I've never asked a question here, but I've made use of many answers so am hoping that the effect I'm hoping to achieve will also help others looking to achieve the same effect.
I'm currently working on a client's website and have uploaded it to my dropbox for this question:
http://dl.dropboxusercontent.com/u/62164771/stage/cw/index16042013.html
It currently uses a few different scripts to achieve the following:
(this script is in the head area)
The navigation menu is fixed, and when you click on a menu link, the page scrolls to the relevant section.
When the page scrolls to the relevant section (after being clicked on), a class (.act) is added to the active menu link. The .act class is also added when the user scrolls up and down in the page with their mouse/track pad or whatever.
(this script is at the bottom of the page)
Another effect is also added to the nav bar links:
When you hover over a nav item, a nav menu indicator arrow (a div with a background image of an arrow) slides across to the hovered link.
So this is what I want to happen
Currently the nav menu indicator arrow only slides on hover. I want it to slide to the active link when it is clicked and stay there until the user hovers on another link. My current script is a little buggy with the menu indicator not always sliding to the active link.
I also want the nav menu indicator arrow to slide to the active link when the user scrolls through the page.
Is this achievable?
Relevant Scripts
Script 1 - scroll smoothly to section and activate 'act' class when scrolling:
<script type="text/javascript">
jQuery(document).ready(function( $ ) {
$('nav a').on('click', function() {
var scrollAnchor = $(this).attr('data-scroll'),
scrollPoint = $('section[data-anchor="' + scrollAnchor + '"]')
.offset().top + 1;
$('body,html').animate({
scrollTop: scrollPoint
}, 500);
return false;
})
$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 100) {
$('#wrap section').each(function(i) {
if ($(this).position().top <= windscroll + 200) {
$('nav a.act').removeClass('act');
$('nav a').eq(i).addClass('act');
}
});
} else {
$('nav').removeClass('fixed');
$('nav a.act').removeClass('act');
$('nav a:first').addClass('act');
}
}).scroll();
})
</script>
Script 2 - For sliding the main-menu-indicator to the position of the hovered and active links
<script type="text/javascript">
$('#header')
.css('position', 'relative')
.append(
$('<div>').attr('id', 'main-menu-indicator')
)
menuHover = function(which){
if(which==null)
which = $('ul#main-menu a.act')
$('#main-menu-indicator')
.stop(true, false)
.animate({
left: ($(which).offset().left - $('#header').offset().left +
$(which).width()/2 + parseInt($(which).css('paddingLeft')) -
$('#main-menu-indicator').width()/2 )
}, 500)
}
$('ul#main-menu a')
.hover(
function(){
menuHover(this)
},
function(){
menuHover(null)
}
)
</script>
You can use Bootstrap ScrollSpy to get the desired effect, it might be easier to implement than writing your own solution. You could start the animation using the activate event.
In your case you could set <a href="#top">, you currently have a section and an article with the same id, you should get rid of one of those as it is invalid html to have more than one element with the same id, and it might break things. For example keep the id on the article: <article class="top area" id="top">. Include the ScrollSpy script on the page and add:
$('.header').scrollspy({activate: function() {
// Add your logic here.
}
});
Inside the activate function $('nav li.active') will give you the currently active li, with that info you should be able to work out where to move your arrow, and you can then run your smooth scrolling arrow code to move the arrow to the right place.
Now ScrollSpy takes care of calling activate when the user scrolls somewhere, and you react on that by moving the arrow to the right place.