Add class to navbar item when scrolling - javascript

Hello I working on create one page website so what I need that for example if the section2 is appear in viewport add class active to link with href = "section2".
Example for what I need one page website
$(document).ready(function () {
$(".links a").click(function (e) {
if (this.getAttribute("href").charAt(0) == "#") {
e.preventDefault();
$(this).addClass("active").siblings().removeClass("active");
$("html, body").stop();
$("html, body").animate({
scrollTop: $($(this).attr("href")).offset().top
}, 1400)
}
else {
$($(this)).attr("target", "_blank")
}
})
})
.links{
width:600px;
position:fixed;
top:0;
padding:20px;
}
.links a{
display:inline-block;
padding:10px 20px;
border:1px solid #02e62a;
color:#02e62a;
text-decoration:none;
}
.links a:hover, .links a.active{
color:#fe0101;
border-color:#fe0101;
}
.section{
width:400px;
height:200px;
margin:300px auto 600px;
background-color:#0094ff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="links">
Section 1
Section 2
External Link
Section 3
Section 4
</div>
<div id="home" class="section"></div>
<div id="about" class="section"></div>
<div id="services" class="section"></div>
<div id="contact" class="section"></div>
Note: please don't recommended me to use any plugin.

Try this, I think it provides you with the solution you want.
$(document).on("scroll", function() {
$('div[id^="section"]').each(function() {
var id = $(this).attr("id");
if (isScrolledIntoView("#" + id)) {
$('a[href="#'+id+'"]').addClass("active").siblings().removeClass("active");
}
})
})
Note it seems to bug a bit when you use it here with mouse scroll, so test it by pulling the scroll bar at the right. Dont know why, but im trying to solve it now.
Update the problem seems to be that snippet window is so small, if you run the example in full page, then it work just fine
$(document).ready(function() {
$(".links a").click(function(e) {
if (this.getAttribute("href").charAt(0) == "#") {
e.preventDefault();
$(this).addClass("active").siblings().removeClass("active");
$("html, body").stop();
$("html, body").animate({
scrollTop: $($(this).attr("href")).offset().top
}, 1400)
} else {
$($(this)).attr("target", "_blank")
}
})
})
$(document).on("scroll", function() {
$('div.section').each(function() {
var id = $(this).attr("id");
if (isScrolledIntoView("#" + id)) {
$('a[href="#'+id+'"]').addClass("active").siblings().removeClass("active");
}
})
})
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));
}
.links {
width: 600px;
position: fixed;
top: 0;
padding: 20px;
}
.links a {
display: inline-block;
padding: 10px 20px;
border: 1px solid #02e62a;
color: #02e62a;
text-decoration: none;
}
.links a:hover,
.links a.active {
color: #fe0101;
border-color: #fe0101;
}
.section {
width: 400px;
height: 200px;
margin: 300px auto 600px;
background-color: #0094ff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="links">
Home
About
External Link
Contact
Blog
</div>
<div id="Home" class="section"></div>
<div id="About" class="section"></div>
<div id="Contact" class="section"></div>
<div id="Blog" class="section"></div>

Related

Display progress bar as scroll in multiple elements

I am trying to create a post page where user scroll to view the posts. There are multiple posts with a sidebar so I want to display a progress bar to indicate the article position.
The code I wrote for this is working good when I navigate to the first element but not for the elements after this.
Here is the code. I tried to set up a fiddle here I want to achieve something like this in the sidebar Reference link
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if (($this.offset().top - $(window).height() / 2 < $(window).scrollTop()) && ($this.offset().top + $this.height() - $(window).height() / 2 > $(window).scrollTop())) {
var s = $(window).scrollTop(),
d = $this.height(),
c = $this.offset().top;
var scrollPercent = (s / (d - c)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>
There's two issues with your code. The first one is that, logically, you would not be wanting to subtract $this.offset().top from $this.height() but rather from $(window).scrollTop() giving you:
var scrollPercent = ((s-c) / (d)) * 100;
The second one is that your logic to switch which article is the currently visible one is convoluted and wrong. The statement you posted switches active article "too early" and therefore returns something a long the lines of "the user read -30% of this article". It is a lot easier to just check for each item whether:
$this.offset().top - $(window).scrollTop() < 0
to determine if it is completely in the viewport.
These two changes give you the following snippet:
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if ($this.offset().top - $(window).scrollTop() < 0) {
var s = $(window).scrollTop()-13,
d = $this.outerHeight(),
c = $this.offset().top;
var scrollPercent = ((s-c) / (d)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>

Add bootstrap class when scrolling the page using jquery

I have a problem with jQuery.
I want to add the fixed-top class (Bootstrap 4) when scrolling the page, but this is not the case.
jQuery(document).ready(function($){
var scroll = $(window).scrollTop();
if (scroll >= 500) {
$(".robig").addClass("fixed-top");
} else {
$(".robig").removeClass("fixed-top");
}
});
Can you see what I'm doing wrong?
Your scroll variable is never being updated. You need to add your code into a scroll event like so:
jQuery(document).ready(function($) {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 130) {
$(".robig").addClass("fixed-top");
} else {
$(".robig").removeClass("fixed-top");
}
});
});
body {
margin: 0;
}
.foo {
height: 140vh;
background: black;
}
.robig {
width: 100%;
height: 10vh;
background: lime;
}
.fixed-top {
position: fixed;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="foo"></div>
<div class="robig"></div>
<div class="foo"></div>
However, if you are trying to recreate a sticking effect, I suggest you use position: sticky as jquery isn't needed for this:
body {
margin: 0;
}
.foo {
height: 140vh;
background: black;
}
.robig {
width: 100%;
height: 10vh;
background: lime;
position: sticky;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="foo"></div>
<div class="robig">Stop at top</div>
<div class="foo"></div>
Your code run on page load only but you need to run your code in scroll event of window
$(window).scroll(function(){
var scroll = $(window).scrollTop();
if (scroll >= 500)
$(".robig").addClass("fixed-top");
else
$(".robig").removeClass("fixed-top");
});
Also you can simplify the code and use .toggleClass() instead
$(window).scroll(function(){
$(".robig").toggleClass("fixed-top", $(window).scrollTop() >= 500);
});
$(window).scroll(function(){
$(".robig").toggleClass("fixed-top", $(window).scrollTop() >= 500);
});
p {height: 500px}
.robig {
width: 100%;
background: red;
}
.fixed-top {
position: fixed;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>content</p>
<div class="robig">robig</div>
<p>content</p>
<p>content</p>
$(document).ready(function(){
var scroll = 0;
$(document).scroll(function() {
scroll = $(this).scrollTop();
if(scroll > 500) {
$(".robig").addClass("fixed-top");
} else {
$(".robig").removeClass("fixed-top");
}
});
});
You need to window scroll event. You can try below code
$(document).ready(function(){
$(window).scroll(function(){
if ($(this).scrollTop() >= 130)
{
$(".robig").addClass("fixed-top");
}
else
{
$(".robig").removeClass("fixed-top");
}
});
});

How to reload a function(event)

I have a div having position: fixed; otherwise at a certain time on scroll down it's having position: absolute;.
My issue is that the position: fixed; of my div depends on the top of my footer. However the top of my footer changes but not the limit of the part where my div should be 'fixed'. Maybe the code would be more clear :
html :
<div id="header" style="height:500px; width:800px; border: 5px solid green; " >
header
</div>
<div id="top" style="height:3000px; width:800px; border: 5px solid yellow; " >
<button onclick="ReduceSize()"> Reduce size </button>
<div id="comment" style="padding-bottom:30px; height:700px; width : 300px; margin-left:30px; border: 5px solid orange;" >
</div>
</div>
<div id="bottom" style="height:3000px; width:800px; border: 5px solid green; " >
footer
</div>
js :
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'>
</script>
<script>
function ReduceSize() {
var obj = document.getElementById('top');
obj.style.height = "750px";
}
$(document).ready(function () {
var haut = $('#comment').offset().top;
var hautBottom = $('#bottom').offset().top - parseFloat( $('#comment').css('height').replace(/auto/, 0) ) ;
$(window).scroll(function (event) {
var y = $(this).scrollTop();
if( (y >= (haut-20) ) && (y < hautBottom ) ) {
$('#comment').css({ position: 'fixed', top:20 });
}else{
if(y >= haut){
$('#comment').css({ position: 'absolute', top:hautBottom });
}
if(y < hautBottom ){
$('#comment').css({ position: 'absolute', top:parseFloat( $('#top').offset().top) });
};
};
});
});
</script>
Thanks in advance.
It is not 100% clear for me, what you want to achieve, but I think this is it:
<!DOCTYPE HTML>
<html>
<head>
<title>Untitled</title>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'></script>
<script>
function ReduceSize() {
$(content).css('height', '600px');
set_comment_position();
}
function set_comment_position(){
var header = $('#header');
var comment = $('#comment');
var footer = $('#footer');
var scroll = $(window).scrollTop();
var header_height = header.outerHeight();
var comment_height = comment.outerHeight();
var comment_distance_top = header_height - scroll;
var footer_offset_top = footer.offset().top;
var footer_distance_top = footer_offset_top - scroll;
var comment_distance_footer = footer_distance_top - comment_height;
if (comment_distance_top <= 0) {
if (comment_distance_footer > 0) {
comment.css({
position: 'fixed',
top: '0px',
bottom : 'auto'
});
} else {
comment.css({
position: 'absolute',
top: 'auto',
bottom: '0px'
});
}
} else {
comment.css({
position: 'absolute',
top: '0px',
bottom : 'auto'
});
}
}
$(document).ready(function(){
set_comment_position()
});
$(window).scroll(function(){
set_comment_position();
});
</script>
</head>
<body>
<div id="header" style="height:100px; width:800px; background-color: lightgreen; " >
header
</div>
<div id="content" style="height:800px; width:800px; background-color: lightgrey; position: relative;" >
<div id="comment" style="height:400px; width : 300px; background-color: orange; position: absolute; top: 0px;" >
comment
<button onclick="ReduceSize()"> Reduce size </button>
</div>
</div>
<div id="footer" style="height:800px; width:800px; background-color: lightgreen; " >
footer
</div>
</body>
</html>
The point is to wrap the positioning logic into one separate function and call this function on docready, scroll and resize.

Making sections stick to top by adding class

I am trying to create a page where as each section reaches the top of the window, it will add a sticky class to the element to it becomes fixed to the top of the page.
I am trying to make the end result look like a bunch of pages that come up and stay at the top of the window
This is my code so far:-
$(document).ready(function(){
var stickyTopSection = $('.home, .about, .gallery, .contact').offset().top;
var stickyTop = function(){
var scrollTop = $(window).scrollTop();
if (scrollTop > stickyTopSection) {
$(this).addClass('sticky');
} else {
$(this).removeClass('sticky');
}
};
stickyTop();
$(window).scroll(function() {
stickyTop();
});
});
.home, .about, .gallery, .contact{
height: 100vh;
width: 100%;
}
.sticky{
position: fixed;
top: 0;
left: 0;
}
.home{
z-index: 1;
background-color: #fff;
}
.about{
z-index: 2;
background-color: #eee;
}
.gallery{
z-index: 3;
background-color: #ddd;
}
.contact{
z-index: 4;
background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<header id="home" class="home">
<h1>Welcome</h1>
</header>
<section id="about" class="about">
<h2>About</h2>
</section>
<section id="gallery" class="gallery">
<h2>Gallery</h2>
</section>
<section id="contact" class="contact">
<h2>Contact</h2>
</section>
You need to check each element individually, and what you have won't do that. Try this...
var stickyTopSections = $('.home, .about, .gallery, .contact');
var stickyTop = function() {
var scrollTop = $(window).scrollTop();
stickyTopSections.each(function() {
var $this = $(this);
if (scrollTop > $this.offset().top) {
$this.addClass('sticky');
}
else {
$this.removeClass('sticky');
}
});
};
stickyTop();
$(window).scroll(function() {
stickyTop();
});
stickyTopSections is a collection of elements, so each has to be parsed individually, hence the use of .each().
Consider using position: sticky, it's designed to solve this exactly problem. Support of it is quite good, but if it's not enough you could youse this great polyfill.
i have try with this other jQuery, is this what you need ?
function isElementInViewport (el) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
$(document).on("scroll", function() {
//console.log("onscroll event fired...");
// check if the anchor elements are visible
$(".common").each(function (idx, el) {
var scrollTop = $(window).scrollTop();
if ( isElementInViewport(el) ) {
// update the URL hash
$(this).addClass('sticky');
}
else {
$(this).removeClass('sticky');
}
});
});
.common {
width:100%;
height:100vh;
}
.home {
background:#666;
}
.about {
background:#999;
}
.gallery {
background:#990;
}
.contact {
background:#06C;
}
<div class="home common"></div>
<div class="about common"></div>
<div class="gallery common"></div>
<div class="contact common"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

hover state not remain fixed when a drop down menu opens?

I am creating a menubar ,here when I hover on element color change to orange, and also when I hover on first and second element of the menu bar a drop down div will be open (menuForHeader).I want when I roll over on this div the color of the first element of the menu bar remain orange.
jquery used
<script>
$(document).ready(function(){
var lastScrollTop = 0
var currentScrollTop = 0
$(window).scroll(function (event) {
lastScrollTop = currentScrollTop
currentScrollTop = $(document).scrollTop()
if (currentScrollTop > lastScrollTop)
{
$('.menuWrap1').css("background-color","black");
}
else
{
if(currentScrollTop==0){
$('.menuWrap1').css("background","linear-gradient(black, transparent)");
$('.menuWrap1').css("background","-o-linear-gradient(black, transparent)");
$('.menuWrap1').css("background","-moz-linear-gradient(black, transparent)");}
}
});
$('#menu2 li:nth-child(2)').mouseover(function(){
$('.menuWrap1').css("height","163px");
});
$('.menuForHeader').mouseover(function(){
$('.menuWrap1').css("height","163px");
});
$('.menuForHeader').mouseout(function(){
$('.menuWrap1').css("height","60px");
});
$('menuForHeader').mouseover(function(){
$('#menu2 li:nth-child(2) a').css("color","orange");
});
$('#menu2 li:nth-child(2)').mouseout(function(){
$('.menuWrap1').css("height","60px");
});
// $('#menu2 li:nth-child(2)').addClass('onHovermenu');
});
</script>
<script type="text/javascript">
var showStaticMenuBar = false;
$(window).scroll(function () {
if (showStaticMenuBar == false) {
//if I scroll more than 200px, I show it
if ($(window).scrollTop() >= 160) {
//showing the static menu
$('.menu').addClass('show');
showStaticMenuBar = true;
}
}
else {
if ($(window).scrollTop() < 200) {
$('.menu').removeClass('show');
showStaticMenuBar = false;
}
}
});
</script>
Html code
<div class="menuWrap1">
<?php echo $this->element('Menus/menuHeader');?>
<div class="menuForHeader">
<?php echo $this->element('Menus/headerServices');?>
</div>
</div>
Css Used
.menuWrap1 {
position:fixed;
right:-21px;
/*margin-left:372px;*/
line-height: 35px;
font-family: 'Oxygen', sans-serif;
letter-spacing: 2px;
height: 60px;
margin-top: -135px;
background: -webkit-linear-gradient(black, transparent);
background: linear-gradient(black, transparent);
background:-o-linear-gradient(black, transparent);
background:-moz-linear-gradient(black, transparent);
transition: height 0.5s ease-in-out;
overflow:hidden;
}
#menu2{
float: right;
margin-right: 200px;
margin-top:-19px;
}
#menu2 li{
display:inline-block;
width:auto;
height:60px;
margin-top:-37px;
padding-right:20px;
}
#menu2 li.menu7{
padding:0;
}
#menu2 li a{
color:white;text-decoration: none;
}
#menu2 li a:active{
color:orange;
}
#menu2 li:nth-child(2) a:hover{
color:orange;
}
Wow this is a toughy. Let's have a try at it:
var innerHeader = $('.menuForHeader');
var menuWrap1 = $('.menuWrap1');
menuWrap1.mouseover(function() {
this.css('color', 'orange');
});
innerHeader.mouseover(function() {
this.css('color', 'orange');
});
innerHeader.mouseout(function() {
this.css('color', 'green');
});
menuWrap1.mouseout(function() {
if (innerHeader.style.color === 'green') {
this.css('color', 'green');
}
});
Using old fashioned DOM properties intermixed with jQuery. LIKE A BAWSS!

Categories