Scrolling issue while sticking header and setting the tab active | Jquery - javascript

I have developed a page, which has a fixed menu once the page is scrolled and also the tabs will become active on their appropriate section id's.
I have almost completed the functionality but I am facing some problems :
Scrolling is not appropriate and it is not stopping at the exact position of the container. Example : If i scroll to section3, the tab should get select once the section3 container hits, but I need to scroll a little bit to get the tab selected.
Once I click on the tab, then the page is getting freezed unable to do any scroll on the page neither able to select any other tab.
i have seen lot of demo's and tried but failed to implement. as per my knowledge i did this demo.
Please help me out with the current code change where I have done wrong.
this is what I tried.
demo Link
HTML:
<div class="top_layer">Top Layer</div>
<div class='menu'>
<ul>
<li>basic 1</li>
<li>basic 2</li>
<li>basic 3</li>
<li>basic 4</li>
</ul>
</div>
<div id="basic1" class="section">basic 1</div>
<div id="basic2" class="section">basic 2</div>
<div id="basic3" class="section">basic 3</div>
<div id="basic4" class="section">basic 4</div>
JS:
var menuSection = $('.section') , navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(), headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function () {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop();
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
navLists.find('a').on('click', function () {
var $el = $(this)
, id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});
});

I have update the code , check fiddle , your navlist selecting anchors should be outsideof window scroll.
var menuSection = $('.section'),
navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(),
headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function() {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop() + 70;//70 for fixed header height
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#' + $(this).attr('id') + '"]').addClass('active');
}
});
});
navLists.find('a').on('click', function() {
var $el = $(this),
id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});

Related

JQuery fadeIn() when element comes into viewport

I would like to fadeIn() different elements as soon as they come into viewport view, when scrolling down a page.
My code however fades in all DIVs (that have the ".fadethis" class) at once, instead of only when that specific element comes into view:
$(window).scroll(function() {
$(".fadethis").each(function() {
var top_of_element = $(this).offset().top;
var bottom_of_element = $(this).offset().top + $(this).outerHeight();
var bottom_of_screen = $(window).scrollTop() + window.innerHeight;
var top_of_screen = $(window).scrollTop();
if((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)){
$(this).fadeIn(10000);
}
});
});
CSS
.fadethis{
display:none;
}
Import jQuery, animate.less and waypoint
Javascript:
$(document).ready(function(){
$('.fromLeft').waypoint(function()
{
$(this.element).css('opacity',1);
$(this.element).addClass("bounceInLeft");
},
{offset:'100%'});
$('.fromRight').waypoint(function()
{
$(this.element).css('opacity',1);
$(this.element).addClass("bounceInRight");
},{offset:'100%'});
$('.appear').waypoint(function()
{
$(this.element).css('opacity',1);
$(this.element).addClass("fadeIn");
},{offset:'100%'});
});
And HTML
<div class="animated onView fromLeft">
appears from left
</div>
Here you can see an example I made

Sticky navigation issue with touch devices

Have created a sticky menu, which is working fine for desktop and mobiles.
But there is a small issue with mobiles, when ever scrolling the page and the finger is still on the screen then
after reaching to the position of the container where the menu needs to stick it is not happening.
When I removed the finger from the screen, then it is taking a second time and the menu is getting fixed.
is there any solution for this, kindly help me with a sample demo.
Demo
JS:
var menuSection = $('.section') , navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(), headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function () {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop()+70;
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
});
navLists.find('a').on('click', function () {
var $el = $(this)
, id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});

Making a menu class active when scrolled past

Note: Using Bootstrap
I want to assign a menu item the 'active' class when the anchor is 50px away from top of the screen. This means that i need to unassign the active class in js and assign a new one.
This is my Menu
<nav class="navbar navbar-default" data-spy="affix" data-offset-top="34">
<div class="container">
<div class="navbar-collapse collapse navbar-responsive-collapse" id="main-menu">
<ul class="nav navbar-nav">
<li id="whatbutton">What We Are</li>
<li id="whybutton">Why Us</li>
<li id="offerbutton">What We Offer</li>
<li id="contactbutton">Contact Us</li>
</ul>
<ul class="nav navbar-nav pull-right">
<li>Right Link</li>
</ul>
</div>
</div>
</nav>
And these are my h1's
<h1 id="whatissm" name="whatissm"><span>sometexthere</span></h1>
<h1 id="whyusesm" name="whyusesm"><span>somtexthere</span></h1>
<h1 id="whatdoessmoffer" name="whatdoessmoffer"><span>sometexthere</span></h1>
<h1 id="contactus" name="contactus"><span>Contact Us</span></h1>
Now this is where I start to struggle...
from an early post i understand that my js should look something like this
<script>
//smooth scrolling
$(function() {
$('[data-toggle="popover"]').popover();
$('[title]').tooltip({container: 'body'});
});
$('a').click(function() {
var reduce = 150;
$('html, body').animate({
scrollTop: $('[name="' + $.attr(this, 'href').substr(1) + '"]').offset().top - reduce
}, 500);
return false;
});
//Making class active by scrolling past it
$(window).scroll(function(){
var scrollTop = $(document).scrollTop();
var anchors = $('body').find('.anchor');
for (var i = 0; i < anchors.length; i++){
if (scrollTop > $(anchors[i]).offset().top - 50 && scrollTop < $(anchors[i]).offset().top + $(anchors[i]).height() - 50) {
$(anchors[i]).addClass('active');
} else {
$(anchors[i]).removeClass('active');
}
}
});
</script>
But unfortunately that code isn't working for me. 1) It doesn't unassign the active class 2) it's just not working.
Edit: Similar to this http://getbootstrap.com/css/ (when you scroll the active class in the right menu changes)
Edit2: Added my code for the scroll down active effect... i'm fairly new to js so i may have implemented it wrong somehow.
EDIT: Understood the actual issue:
$(window).scroll(function(){
var scrollTop = $(document).scrollTop();
var anchors = $('body').find('h1');
for (var i = 0; i < anchors.length; i++){
if (scrollTop > $(anchors[i]).offset().top - 50 && scrollTop < $(anchors[i]).offset().top + $(anchors[i]).height() - 50) {
$('nav ul li a[href="#' + $(anchors[i]).attr('id') + '"]').addClass('active');
} else {
$('nav ul li a[href="#' + $(anchors[i]).attr('id') + '"]').removeClass('active');
}
}
});
Same technique; checking if each of your h1 elements are both below the elements top position and above the elements bottom position. If true, get the id of the element and select the corrosponding navigation item and add active class to it.
Updated fiddle: http://jsfiddle.net/yrz54fqm/1/
Old answer
Following code should give you the result you're looking for
$(window).scroll(function(){
var scrollTop = $(document).scrollTop();
var anchors = $('body').find('.anchor');
for (var i = 0; i < anchors.length; i++){
if (scrollTop > $(anchors[i]).offset().top - 50 && scrollTop < $(anchors[i]).offset().top + $(anchors[i]).height() - 50) {
$(anchors[i]).addClass('active');
} else {
$(anchors[i]).removeClass('active');
}
}
});
You need to listen for the scroll event on the window, and check if each of your elements are both below the elements top position and above the elements bottom position.
Replace the var anchors = $('body').find('.anchor'); on line 3 with whatever the anchor class names are in your situation. Here's a fiddle with HTML and CSS aswell: http://jsfiddle.net/yrz54fqm/
Hope it helps :)
/**
*
* #param {Element} - element 1 that used to get offset when scrolling
* #param {Element} - activated when passing element 1
* #param {String} - class name to add to element 2 when element 1 is passed
*/
this.ScrollBetween = function(targetElement, pElement, className) {
$(window).scroll(function() {
var scrollTop = $(window).scrollTop(),
targetOffsetTop = $(targetElement).offset().top,
targetHeight = $(targetElement).height();
(scrollTop > targetOffsetTop - 50 && scrollTop < targetOffsetTop + targetHeight - 50 ? $(pElement).addClass(className) : $(pElement).removeClass(className));
});
};
Made a function so it way easier to understand. Right now it is used in a JQuery Object but can be simply changed to regular function by changing it to
function ScrollBetween(targetElement, pElement, className){
.............
}
Can be called by
ScrollBetween($("#section-1"), $("li-1"), "active");

Change link attribute when scrolling to anchor

Can someone please put me out of my misery and 'fix' or 'solve' my issue: as you can see via my JSfiddle link
http://jsfiddle.net/SJkmh/312/
jQuery(document).ready(function ($) {
var h = $("#main-menu").height() * 1.25;
$(".scroll").click(function (event) {
event.preventDefault();
$('html,body').animate({
scrollTop: $(this.hash).offset().top - h
}, 300);
});
I can't seem to get it to work - all I want to do is change the colour of the link text to identify what section of the page the user is on. please help me?
Thanks in advance
UPDATE : Select menu item on scroll
[UPDATED] jsFiddle : http://jsfiddle.net/thecbuilder/Qtjx6/2/
added js
$(window).scroll(function () {
// Get container scroll position
var topHeight = $(this).scrollTop() + h + 10;
var onTopId;
$(".testx").each(function () {
var curTop = $(this).offset().top;
var curBottom = curTop + $(this).height();
if (curTop < fromTop && curBottom > topHeight) {
onTopId = $(this).attr("id");
}
});
$selLink.removeClass("selected");
$selLink = $("a[href=#"+onTopId+"]").addClass("selected");
});
This should do the task : http://jsfiddle.net/thecbuilder/Qtjx6/
js
var $selLink = $("ul li a");
$(function(){
$("ul li a").click(function(){
$selLink.removeClass("selected");
$selLink = $(this);
$selLink.addClass("selected");
});
});
css
.selected{
color : #4B85C3;
}
You are checking the offset of the links not the content sections. Working fiddle:
http://jsfiddle.net/SJkmh/315/
$(document).scroll(function () {
var h = $("#main-menu").height() * 1.5;
var link1 = $("#home").offset().top;
var link2 = $("#about").offset().top;
var link3 = $("#work").offset().top;
var selectedColor = "#4B85C3";
var defaultColor = "#2e375b";
var top = $(this).scrollTop() - h;
$("#main-menu li a").css('color', defaultColor);
if (top <= link1) {
$("#link1").css('color', selectedColor);
} else if (top <= link2) {
$("#link2").css('color', selectedColor);
} else {
$("#link3").css('color', selectedColor);
}
});
The way to do this would be to reset the color of all the links, and then set the color of the $(this) to the new color
jQuery(document).ready(function ($) {
var h = $("#main-menu").height() * 1.25;
$(".scroll").click(function (event) {
$('a.scroll').css({"color": "#2e375b"});
$(this).css({"color": "#4B85C3"});
event.preventDefault();
$('html,body').animate({
scrollTop: $(this.hash).offset().top - h
}, 300);
});
});
JSFiddle

Is there a better way to achieve the same results? One Page Websites

I am trying to create a website with only one page but has different sections within it, you can navigate using the menu and it will scroll you to the selected section.
Here is a live preview of a website I have created using the technique you will see below:
http://spacehopperdesign.co.uk
Please view this Fiddle for the HTML and JavaScript I am using, ignore the CSS as it does nothing: http://jsfiddle.net/J2kjA
My problem is: I want the buttons to gain the class .active when their section is shown, I know I managed to get it working as you have noticed in the live preview. But as you will see in the Fiddle, the JS I am using is a bit complex and I it is really confusing especially when working on a big project with many sections with it.
Is there anyway to achieve the same results using much simpler way? I prefer not using Plugins please. Any help or advice will be much appreciated.
Here is the JS anyway as well:
$(document).ready(function() {
//Prevent clicking on .active links
'use strict'; $('.active').click(function(a) {
a.preventDefault();
});
//Menu Scrolling To Sections//
$(document).ready(function () {
$('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) {
var topPadding = 50;
if($(window).width() > 1030)
topPadding = 80;
$('html,body').animate({
scrollTop: target.offset().top - topPadding }, 700);
return false;
}}});
});
$(window).scroll(function(){
var scrollHeight = $(window).scrollTop() + 200;
var index = $('#Index').offset().top;
var sectionA = $('#SectionA').offset().top;
var sectionB = $('#SectionB').offset().top;
var sectionC = $('#SectionC').offset().top;
$('#mainMenu li a').removeClass('active');
if(scrollHeight >= index && scrollHeight < sectionA)
$('#index').addClass('active');
if(scrollHeight >= sectionA && scrollHeight < sectionB)
$('#sectionA').addClass('active');
if(scrollHeight >= sectionB && scrollHeight < contact)
$('#sectionB').addClass('active');
if(scrollHeight >= sectionC)
$('#sectionC').addClass('active');
});
});
and the HTML:
<header id="headerWrapper">
<div id="headerContent">
<nav>
<ul id="mainMenu"><!--Main Menu-->
<li><a class="active" href="#Index" id="index">Welcome</a></li>
<li>SectionA</li>
<li>SectionB</li>
<li>Contact</li>
</ul>
</nav>
</div>
</header>
<div id="page"><!--Main Container-->
<div id="Index" class="wrapper">
<div class="content">
</div>
</div>
<div id="SectionA" class="wrapper">
<div class="content">
</div>
</div>
<div id="SectionB" class="wrapper">
<div class="content">
</div>
</div>
<div id="SectionC" class="wrapper">
<div class="content">
</div>
</div>
</div>
Have you tried using JQuery to add a class to the button? TESTED AND WORKS http://jsfiddle.net/J2kjA/7/
First add another class and data to each of the buttons:
<li><a class="btn active" data-btn="index" href="#Index" id="index">Welcome</a></li>
<li><a class="btn" data-btn="sectionA" href="#SectionA" id="sectionA">SectionA</a></li>
<li><a class="btn" data-btn="sectionB" href="#SectionB" id="sectionB">SectionB</a></li>
<li><a class="btn" data-btn="sectionC" href="#SectionC" id="sectionC">Contact</a></li>
And for the JavaScript:
$(document).ready(function() {
//Prevent clicking on .active links
'use strict'; $('.active').click(function(a) {
a.preventDefault();
});
//Menu Scrolling To Sections//
$(document).ready(function () {
$('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) {
var topPadding = 50;
if($(window).width() > 1030)
topPadding = 80;
$('html,body').animate({
scrollTop: target.offset().top - topPadding }, 700);
return false;
}
}
});
});
$(window).scroll(function(){
var scrollHeight = $(window).scrollTop() + 200;
var index = $('#Index').offset().top;
var sectionA = $('#SectionA').offset().top;
var sectionB = $('#SectionB').offset().top;
var sectionC = $('#SectionC').offset().top;
});
});
$(function(){
$('.btn').on('click', function(){
var btn = $(this).data("btn");
$('#index').removeClass("active");
$('#sectionA').removeClass("active");
$('#sectionB').removeClass("active");
$('#sectionC').removeClass("active");
$('#'+btn).addClass ("active");
});
});
http://api.jquery.com/removeClass/
Maybe this:
$(document).ready(function() {
$('#mainMenu a').click(function() {
$('#mainMenu a').removeClass('active');
$(this).addClass('active');
});
if(scrollHeight >= index && scrollHeight < sectionA)
{$('#index').trigger('click');} //etc
});
I found this function for you:
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
This checks if an element is visible after scrolling. You can call it whenever the page is scrolled and check whatever you need for each of the elements.
$(window).scroll(function(){
if(isScrolledIntoView($('#SectionA'))){
$('#sectionA').addClass('active');
}
}

Categories

Resources