How to keep class active when scrolling with javascript? - javascript

I need help figuring out what is going on with my javascript. I have some code that is supposed to make the nav links have an active class when you are on that part of the page, but it's only sort of working for a couple links and it also flickers as you scroll rather than staying active the whole time you're on that part of the page. See the JSFiddle for an example https://jsfiddle.net/7szpuqsr/ -- if you scroll slowly you can see how "home" becomes active for a moment. I am trying to get each link to have the active class when you click it and also while you are on that entire part of the page.
I also have a javascript sticky nav bar and smooth scrolling working so I don't know if possibly any of that is getting in the way? Thanks in advance for help.
Here's the Javascript I'm trying to use for the active class:
var sections = $('section')
, nav = $('nav')
, nav_height = nav.outerHeight();
$(window).on('scroll', function () {
var cur_pos = $(this).scrollTop();
sections.each(function() {
var top = $(this).offset().top - nav_height,
bottom = top + $(this).outerHeight();
if (cur_pos >= top && cur_pos <= bottom) {
nav.find('a').removeClass('active');
sections.removeClass('active');
$(this).addClass('active');
nav.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
});
nav.find('a').on('click', function () {
var $el = $(this)
, id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - nav_height
}, 500);
return false;
});

Something like this? I couldn't reproduce the flickering visually on my machine but I can see the class being removed/added constantly on scroll
https://jsfiddle.net/7szpuqsr/1/
Main changes, I added a class to your sections, you have too many sections but with the way your code is meant to work, it's much easier to add a class to the sections, example below
<section id="home" class="section">
var sections = $('.section') to get the section class
updated this part of the js to check for active class
if (cur_pos >= top && cur_pos <= bottom) {
if(!$(this).hasClass("active")) {
nav.find('a').removeClass('active');
sections.removeClass('active');
$(this).addClass('active');
nav.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
}
You can also cache the $(this) into a variable inside of the section loop like
var $this = $(this);
then just use $this for the rest of the loop
here is the doc for hasClass https://api.jquery.com/hasclass/

Related

How to change the 'sections' to changeable class or id?

I have this well working code for my onepager, and need to change the target on this. How can I change 'sections' to any class or id?
I tried to add a class like ('.target') but it did not work.
var sections = $('section')
, nav = $('nav')
, nav_height = nav.outerHeight();
$(window).on('scroll', function () {
var cur_pos = $(this).scrollTop();
sections.each(function() {
var top = $(this).offset().top - nav_height,
bottom = top + $(this).outerHeight();
if (cur_pos >= top && cur_pos <= bottom) {
nav.find('a').removeClass('active');
sections.removeClass('active');
$(this).addClass('active');
nav.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
});
I need this code to work with class or id to have different targets than sections.
Other solution for me could be also: To add something like (top: -100px;) on scrolling. I have a fixed navigation bar and need the script to leave space on top.

highlighting current section on scroll - gap between sections

I have a page with different sections that can be scrolled to or accessed by clicking the corresponding link in the navbar. A demo of the page is on codepen http://codepen.io/meek/pen/NNprYb?editors=1010
I am using the following code to keep track of which section the user is scrolling over and highlighting it in the navbar
$(window).on("scroll", function() {
var currentPos = $(window).scrollTop();
$('.nav li a').each(function() {
var sectionLink = $(this);
var section = $(sectionLink.attr('href'));
if(section.position().top <= currentPos && section.position().top + section.height() > currentPos) {
$('.nav li').removeClass('active');
sectionLink.parent().addClass('active');
}
else {
sectionLink.parent().removeClass('active');
}
});
});
It works fine, but there is a gap where scrolling through between home and about sections, none of the links are highlighted. I have a feeling this might be because of the space the navbar occupies between home and about, but I'm not sure how to overcome this. Ideally, I'd like to have that gap also highlight "about".
I've tried to add this to the above code:
else if($('#nav-wrapper').position().top <= currentPos && $('#nav-wrapper').position().top + $('#nav-wrapper').height() > currentPos) {
$('.nav li').removeClass('active');
$('#temp').addClass('active');
}
but it doesn't work. Help appreciated
Solution:
Adjust your if statement in your scroll event to match the following.
if(section.position().top <= currentPos && sectionLink.offset().top + section.height() > currentPos)
The key being, the second instance of section.position().top changes to sectionLink.offset().top

Image highlight (hover state) on active section while scrolling?

I have these icons above each section on my page (the largish circular icons, please see example: http://pftest.fhero.net) with colored hover states... what I would really love to do is have them change to the active hover states as the user scrolls to each section (preferably with a simple fade transition) - much like the effect of highlighting the active links/section in the navigation.
There are many tutorials, plugins and questions on this site and so forth for highlighting active sections in a navigation however, but doesn't seem to be much that I can find relating to applying the effect to another div or image on the page...
I'm definitely not any kind of jQuery expert but I'm wondering if one of the myriad of scripts/plugins available which are typically used for highlighting active states in navigation could simply be adapted to this scenario somehow to achieve the same effect? Perhaps even the one I am currently using on my page?
Here is the script I'm using for highlighting the active section in the navigation on my page:
/* Scroll Navigation highlight */
$("#work-section1").parent().addClass('active');
var main = main = $('#mainmenu ul');
$('.scroll').click(function(event) {
event.preventDefault();
var full_url = this.href,
parts = full_url.split('#'),
trgt = parts[1],
target_offset = $('#'+trgt).offset(),
target_top = target_offset.top;
$('html, body').animate({scrollTop:target_top}, 500);
/* Remove active class on any li when an anchor is clicked */
main.children().removeClass();
/* Add active class to clicked anchor's parent li */
$(this).parent().addClass('active');
});
$(window).scroll(function(event) {
if($("#work-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#work-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#footer-section").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#about-section").offset().top < $(window).scrollTop() + $(window).outerHeight()) {
$("#about-section1").parent().addClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#services-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#services-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#process-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#process-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
}
if($("#footer-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#footer-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
});
and the HTML:
<nav id="mainmenu" name="mainmenu">
<ul>
<li><a class="scroll" id="work-section1" href="#work-section">Works</a></li>
<li><a class="scroll" id="about-section1" href="#about-section">About</a></li>
<li><a class="scroll" id="services-section1" href="#services-section">Services</a></li>
<li><a class="scroll" id="process-section1" href="#process-section">Process</a></li>
<li><a class="scroll" id="footer-section1" href="#footer-section">Contact</a></li>
</ul>
</nav>
<section id="about-section" data-anchor-offset="90">
<section id="work-section" data-anchor-offset="90">
...ect...
Could this somehow be adapted to accomplish the effect I am looking for? Or any other/better methods, or plugins I should be looking at?
I should add that the icons use the sprites method which could make the CSS side of things a little trickier, although I would be willing to change them to non-sprite images if necessary...
You could use a small little function for this, that checks if a element is on screen. I set up a little JSFiddle for you: http://jsfiddle.net/LHrkB/1/
Code:
function isElementVisible(elementToBeChecked)
{
var TopView = $(window).scrollTop();
var BotView = TopView + $(window).height();
var TopElement = $(elementToBeChecked).offset().top;
var BotElement = TopElement + $(elementToBeChecked).height();
return ((BotElement <= BotView) && (TopElement >= TopView));
}
$(window).scroll(function () {
isOnView = isElementVisible(".inview");
if(isOnView){
//What to do when element is visible
$(".inview").css({"background":"#ccc"});
}else{ // If not visible
}
});
Ok, so i have changed the JSFiddle a bit, now it uses a fadeIn on a invisible element when it comes into view: http://jsfiddle.net/LHrkB/2/
Ok, i changed the JSFiddle once again. When you scroll in the results pane, and you play around with it a bit you can see the element change class as it comes on screen and also when it goes away again. I commented the JS so you can see what it does and where it does it. http://jsfiddle.net/LHrkB/4/
Thanks to the help of Veritas87 (who is super awesome), managed to get it all working with the following code:
function isElementVisible(elementToBeChecked)
{
var TopView = $(window).scrollTop();
var BotView = TopView + $(window).height();
var TopElement = $(elementToBeChecked).offset().top;
var BotElement = TopElement + $(elementToBeChecked).height();
return ((BotElement <= BotView) && (TopElement >= TopView));
}
$(window).scroll(function () {
isOnView = isElementVisible(".about-icon");
if(isOnView){
//What to do when element is visible
$('.about-icon').addClass('about-icon-active');
}else{ // If not visible
$('.about-icon').removeClass('about-icon-active');
}
isOnView = isElementVisible(".works-icon");
if(isOnView){
//What to do when element is visible
$('.works-icon').addClass('works-icon-active');
}else{ // If not visible
$('.works-icon').removeClass('works-icon-active');
}
isOnView = isElementVisible(".services-icon");
if(isOnView){
//What to do when element is visible
$('.services-icon').addClass('services-icon-active');
}else{ // If not visible
$('.services-icon').removeClass('services-icon-active');
}
isOnView = isElementVisible(".process-icon");
if(isOnView){
//What to do when element is visible
$('.process-icon').addClass('process-icon-active');
}else{ // If not visible
$('.process-icon').removeClass('process-icon-active');
}
});
with the "...icon-active" classes of course containing the style for the icon hover states.

Update scroll position on resize of window

I'm currently using a combination of smooth scroll and IDs/anchor tags to scroll to content on my site. The code below is getting the ID of the next 'section' in the DOM, and adding it's ID as the 'view next section' href, so once it's clicked, it'll scroll to the top of that div. Then, it iterates through, updating the href with the next ID each time etc until the last section is seen and it scrolls back to the top. Pretty straightforward.
The only problem is that the 'sections' are fullscreen images, so as it's scrolling to the top of the next section, if you resize the browser, the top position of that section (where we scrolled to) has moved, and means the position is lost.
I've created a JSFiddle. You can see this happening after you click the arrow to visit the next section then resize the window: http://jsfiddle.net/WFQ9t/3/
I'm wanting to keep this top position fixed at all times so even if you resize the browser, the scroll position is updated to reflect this.
Thanks in advance,
R
var firstSectionID = $('body .each-section').eq(1).attr('id');
$('.next-section').attr('href', '#' + firstSectionID);
var i = 1;
$('.next-section').click(function() {
var nextSectionID = $('body .each-section').eq(i).attr('id');
i++;
$('.next-section').attr('href', '#' + nextSectionID);
var numberOfSections = $('body .each-section').length;
var lastSectionID = $('body .each-section').eq(numberOfSections).attr('id');
if ($('.next-section').attr('href') == '#' + lastSectionID ) {
$('.next-section').attr('href', '#introduction');
i = 1;
}
});
Ok, Please check out this fiddle: http://jsfiddle.net/WFQ9t/9/
The few things I did were:
Made some global variables to handle the screen number (which screen you're on and also the initial window height. You will use this when the screen loads and also when you click on the .next-session arrow.
var initWinHeight = $(window).height();
var numSection = 0;
Then I tossed those variables into your resizeContent() function
resizeContent(initWinHeight, numSection)
so that it will work on load and resize
I made the body move around where it needs to, to accomodate for the movement of the divs (I still don't understand what divs are moving when the regular animation happens).
$('body').css({
top: (((windowHeight - initWinHeight)*numSection)*-1) + "px"
});
Then in your click function, I add 1 to the section number, reset the initial window height and then also reset the body to top:0. The normal animation you have already puts the next section at the top of the page.
numSection++;
initWinHeight = $(window).height();
$('body').css({top:"0px"}, 1000);
Finally, I reset the numSections counter when you reach the last page (You might have to make this 0 instead of 1)
numSection = 0;
The fiddle has all of this in the correct places, these are just the steps I took to change the code.
Here is a solution that i found, but I dont use anchor links at this point, i use classes
Here is my HTML code:
<section class="section">
Section 1
</section>
<section class="section">
Section 2
</section>
<section class="section">
Section 3
</section>
<section class="section">
Section 4
</section>
And here is my jQuery/Javascript code,
I actually used a preety simple way:
$('.section').first().addClass('active');
/* handle the mousewheel event together with
DOMMouseScroll to work on cross browser */
$(document).on('mousewheel DOMMouseScroll', function (e) {
e.preventDefault();//prevent the default mousewheel scrolling
var active = $('.section.active');
//get the delta to determine the mousewheel scrol UP and DOWN
var delta = e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0 ? 1 : -1;
//if the delta value is negative, the user is scrolling down
if (delta < 0) {
next = active.next();
//check if the next section exist and animate the anchoring
if (next.hasClass('section')) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: next.offset().top
}, 800);
next.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
} else {
prev = active.prev();
if (prev.length) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: prev.offset().top
}, 800);
prev.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
}
});
/*THE SIMPLE SOLUTION*/
$(window).resize(function(){
var active = $('.section.active')
$('body, html').animate({
scrollTop: active.offset().top
}, 10);
});

Page Scrolling jQuery Navigation

I am building a website which can be viewed here: argit.bounde.co.uk
I have done the majority of the content and I am now trying to work on the navigation. I have three navigation bars (only one is ever visible) and need this method to work no matter which is showing. If you resize your browser to make your window narrower that will show a second, and then when you scroll the navigation that appears is a third.
I have got it working to a fashion but the problem is when I click a link it jumps to where it wants to go momentarily, then returns and then scrolls as it is meant to. This is because of the "href="#target" that i have left in the nav. I have tried including a "return false" but then if the broswer doesnt support JS then the navigation doesnt work at all.
The next problem is I want a way to make the target "over". Currently when you click a link it scrolls to the selected one and the nav updates which link is "over" as it passes them. I want this for when the user is scrolling up and down the page, but if they click a link I want that link to be "over" (and the respective links from other navigations) and not be affected by the scroll checks that would normally override it.
The solution I am using for my onClick navigation is below, I know there are plug ins that will do this kind of thing but I want to write it myself so i can get a better understanding of jQuery. Im not sure if the solution I am using at the moment is a good one, if not please advise me:
function navigation() {
$('html, body').stop().animate({
scrollTop: $($(this).attr('href')).offset().top
}, 1500);
}
The solution I am using for the scrolling checks I found by accident and is below, It works by over riding the equation above it and is actually quite simple. There is also an action to fix the navigation when scrolling.
function navCheck() {
var documentHeight = $(document).height();
var windowHeight = $(window).height();
var windowTop = $(window).scrollTop() + 100;
var navTop = $("#scrollanchor").offset().top;
var mobileTop = $("#mobileanchor").offset().top;
var mobileHeight = $("#mobileanchor").height();
var overviewTop = $("#slider").offset().top;
var bioTop = $("#bio").offset().top;
var solutionsTop = $("#solutions").offset().top;
var experianceTop = $("#experiance").offset().top;
var contactTop = $("#contact").offset().top;
if($(window).scrollTop() > navTop) {
$("#leftfixer").addClass("leftfix");
} else {
$("#leftfixer").removeClass("leftfix");
}
if($(window).width() < 1200){
if(windowTop - 90 > mobileTop + mobileHeight) {
$("#mobilefix").slideDown();
} else {
if(windowTop - 96 <= mobileTop) {
$("#mobilefix").hide();
}
}
} else {
$("#mobilefix").slideUp();
}
$("li").removeClass("over");
$("li.navoverview").addClass("over");
if(windowTop > bioTop) {
$("li").removeClass("over");
$("li.navbio").addClass("over");
}
if(windowTop > solutionsTop) {
$("li").removeClass("over");
$("li.navsolutions").addClass("over");
}
if(windowTop > experianceTop) {
$("li").removeClass("over");
$("li.navexperiance").addClass("over");
}
if(windowTop > contactTop || windowTop > documentHeight - windowHeight) {
$("li").removeClass("over");
$("li.navcontact").addClass("over");
}
}
This is my first post here so if I have missed out any information Im sorry! I have also looked for similar posts but it seems most people go for a plugin when doing this kind of thing. Thank you
UPDATE: The page jumping to the anchor has been fixed
Normally, if you use JavaScript to scroll the page, you would put return false; after calling the function. This prevents the page from scrolling momentarily to the anchor.
Something like
function navigation() {
$('html, body').stop().animate({
scrollTop: $($(this).attr('href')).offset().top
}, 1500);
return false;
}

Categories