Stick div at top not working properly : javascript - javascript

I going to create a scroll and stick div which has to stick on the top of the page but while scrolling down the div next to stickdiv automatically stick to the div before to sticky div
var left = document.getElementsByClassName("stickdiv");
for (var i = 0; i < left.length; i++) {
var stop = (left[0].offsetTop);
window.onscroll = function(e) {
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
// left.offsetTop;
if (scrollTop >= stop) {
// get array item by index
left[0].classList.add('stick'); //adding a class name
} else {
// get array item by index
left[0].classList.remove('stick');
}
}
}
.stickdiv {
height: 50vh!important;
width: 100vh!important;
background-color: green!important;
}
.stick {
position: fixed;
top: 0;
margin: 0 0
}
#right {
float: right;
width: 100px;
height: 1000px;
background: red;
}
.des {
height: 300px;
width: 100%;
background-color: #000;
}
<div class="des"></div>
<div class="stickdiv"></div>
<div id="right"></div>
Example : green color div is the sticky div but after scrollingdown , red is also going to stick , I've tried position absolute in css but not working how to fix it

Here is the code to make green sticky when scrolling.
$ = document.querySelectorAll.bind(document);
// how far is the green div from the top of the page?
var initStickyTop = $(".stickdiv")[0].getBoundingClientRect().top + pageYOffset;
// clone the green div
var clone = $(".stickdiv")[0].cloneNode(true);
// hide it first
clone.style.display = "none";
// add it to dom
document.body.appendChild(clone);
addEventListener("scroll",stick=function() {
// if user scroll past the sticky div
if (initStickyTop < pageYOffset) {
// hide the green div but the div still take up the same space as before so scroll position is not changed
$(".stickdiv")[0].style.opacity = "0";
// make the clone sticky
clone.classList.add('stick');
// show the clone
clone.style.opacity="1";
clone.style.display = "block";
} else {
// make the clone not sticky anymore
clone.classList.remove("stick");
// hide it
clone.style.display = "none";
// show the green div
$(".stickdiv")[0].style.opacity="1";
};
});
// when resize, recalculate the position of the green div
addEventListener("resize", function() {
initStickyTop = $(".stickdiv")[0].getBoundingClientRect().top + pageYOffset;
stick();
});
.stickdiv {
height: 50vh!important;
width: 100vh!important;
background-color: green!important;
}
.stick {
position: fixed;
top: 0;
margin: 0 0
}
#right {
float: right;
width: 100px;
height: 1000px;
background: red;
}
.des {
height: 300px;
width: 100%;
background-color: #000;
}
<div class="des"></div>
<div class="stickdiv"></div>
<div id="right"></div>

JS FIDDLE
you might want to remove the stickdiv class and add it accordingly
if (scrollTop >= stop) {
// get array item by index
left[0].classList.add('stick'); //adding a class name
left[0].classList.remove('stickdiv');
} else {
// get array item by index
left[0].classList.remove('stick');
left[0].classList.add('stickdiv');
}

Related

Move element by certain amount while scrolling

I want to move the white box to the right by 50% while scrolling until it reaches the red section. The distance to the red section is 1000px in the example.
The code below moves the box to the right as I scroll down, and I'm just using a random number 10 to slow down the movement but I can't get my head around to make it move evenly for every scroll event until the box reaches the red section and move 50% to the right.
var xPos = 0;
function getXPos(target, windowPos) {
var amount = windowPos - target;
xPos = amount / 10;
return xPos;
}
$(window).scroll(function() {
var windowPos = $(window).scrollTop();
var sectionOne = $('section.one').offset().top;
var sectionTwo = $('section.two').offset().top;
var box = $('.box');
if (windowPos > sectionOne && windowPos < sectionTwo) {
box.css({
"transform": 'translateX(' + getXPos(sectionOne, windowPos) + '%)'
});
}
});
body {
margin: 0;
}
.box {
background: white;
position: sticky;
top: 0;
width: 300px;
height: 300px;
}
section.one {
height: 1000px;
background: blue;
}
section.two {
height: 1000px;
background: red;
}
<section class="one">
<div class="box"></div>
</section>
<section class="two"></section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
There is also another issue with scroll that if I scroll too fast, the box won't move as much.
Here is the fiddle for demonstration.
https://jsfiddle.net/sungsoonz/0Lspo2d9/
So I used the logic of making a progress bar for whole page but for your section with class "one". So when you scroll the section 100% of it's height the "left" css property on the div with class "box" becomes at value of "100%". But as I understood we need to stop moving when we reach section with class "two" with div with class "box". So {left: 100%} will become when we have scrolled whole section with class "box" minus the visible height of div with class "box". Then it is easily calculated to move only for 50% of width of section with class "one" (-width of div with class "box" width / 2 to center it). Hope I described my solution clearly (xd). Hope it helps
The code:
one = document.querySelector(".one")
two = document.querySelector(".two")
box = document.querySelector(".box")
$(window).on('scroll', function (){
if (window.scrollY >= (one.scrollHeight - box.offsetHeight)) {
$('.box').css('left', `calc(50% - ${(box.offsetWidth / 2)}px`);
return
}
$scrolledFrom = $(document).scrollTop();
$documentHeight = $(document).height() - ($(".two").height() + box.offsetHeight);
$leftOffset = ($scrolledFrom / $documentHeight) * 100;
$('.box').css('left', `calc(${($leftOffset / 2)}% - ${(box.offsetWidth / 2)}px`);
console.log ()
});
body {
margin: 0;
}
.box {
background: white;
position: sticky;
top: 0;
left: 0;
width: 300px;
height: 300px;
}
section.one {
height: 1000px;
background: blue;
}
section.two {
height: 1000px;
background: red;
}
<section class="one">
<div class="box"></div>
</section>
<section class="two"></section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

How to change the text color of a transparent header on scroll, depending on the div it overlaps

I have a header with a transparent backgrounsd, and I am trying to get the text of the header to change colour between white and black depending on the background of the div it's overlapping.
So far I have managed to add a class of .color-menu to all the divs where I want the header to be black.
I then have it add a class of .dark-menu to the header when the .color-menu div reaches the top of the page.
The problem is that it only works for the first .colour-menu div. It will change to black when it is in the viewport and back to white for the next div but then when the next .color-menu div gets to the top it doesn't change.
So, it seems like the .each function isn't working but I am not sure how to fix it.
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(".color-menu").offset().top;
var bottom_of_element = $(".color-menu").offset().top + $(".color-menu").outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
UPDATE: I have also tried using $(this) but it really throws off when it changes color.
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(this).offset().top;
var bottom_of_element = $(this).offset().top + $(this).outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
Here is a simplified version of my code as an example:
$(document).ready(function() {
$(".white").addClass("color-menu");
$(".white-bold").addClass("color-menu");
$(".light").addClass("color-menu");
$(".light-bold").addClass("color-menu");
$(".bright").addClass("color-menu");
});
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(".color-menu").offset().top;
var bottom_of_element = $(".color-menu").offset().top + $(".color-menu").outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
.header {
width: 100%;
background: rgba(0,0,0,0);
margin: 0;
padding:10px;
position: fixed;
text-align: center;
}
.header a {
color: white;
font-size: 2rem;
text-transform: uppercase;
}
.dark-menu a{
color: black;
}
.black {
background-color: black;
height: 200px;
}
.white, .white-bold, .light, .light-bold, .bright {
background-color: white;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<a>This is the header</a>
</div>
<div class ="black"></div>
<div class ="white"></div>
<div class ="black"></div>
<div class ="white-bold"></div>
<div class ="black"></div>
<div class ="light"></div>
<div class ="black"></div>
<div class ="light-bold"></div>
<div class ="black"></div>
<div class ="bright"></div>
What is happening in your code is that on scroll, you loop through every color-menu div and add the class if it is the current one... but then the code continues to loop though the remaining elements in the array and removes it again because the page is not in the other div.
I've explained step-by-step the changes you need to get this to work after the example, but first you can see it working here:
Working Example:
$(document).ready(function() {
$(".white").addClass("color-menu");
$(".white-bold").addClass("color-menu");
$(".light").addClass("color-menu");
$(".light-bold").addClass("color-menu");
$(".bright").addClass("color-menu");
$(window).scroll(function() {
var inColorMenu = false; /* initialise var to store if we are in color-menu */
var top_of_screen = $(window).scrollTop(); /* just get this once outside loop */
/* Loop through each color-menu element and check if we are in one */
$('.color-menu').each(function(i) {
var top_of_element = $(this).offset().top;
var bottom_of_element = top_of_element + $(this).outerHeight();
/* if we are in a color-menu element, set our var to true and stop processing */
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
inColorMenu = true;
return false; /* N.B. need to return "false" to break from the "each" loop */
}
});
if (inColorMenu) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
.header {
width: 100%;
background: rgba(0, 0, 0, 0);
margin: 0;
padding: 10px;
position: fixed;
text-align: center;
}
.header a {
color: white;
font-size: 2rem;
text-transform: uppercase;
}
.header.dark-menu a {
color: black;
}
.black {
background-color: black;
height: 200px;
}
.white,
.white-bold,
.light,
.light-bold,
.bright {
background-color: white;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<a>This is the header</a>
</div>
<div class="black"></div>
<div class="white"></div>
<div class="black"></div>
<div class="white-bold"></div>
<div class="black"></div>
<div class="light"></div>
<div class="black"></div>
<div class="light-bold"></div>
<div class="black"></div>
<div class="bright"></div>
How this works:
Declare a variable to record whether we are in a "color-menu" class or not, and initialise this to false, e.g.:
var inColorMenu = false;
When looping through $('.color-menu').each, if we are between the top and bottom of one of divs (which your code is already detecting), then set our variable to true to record this.
We can also return false to break the each loop and stop processing the rest of the elements (it will still work without this, we are just reducing the amount of processing required):
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
inColorMenu = true;
return false; /* N.B. need to return "false" to break from the "each" loop */
}
Finally, after we finish our $('.color-menu').each loop, if inColorMenu is true, we know we are in a color-menu div so we add the dark-menu class to the header, otherwise we remove it:
if (inColorMenu) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
Note: You need to use $(this) when getting the offset().top and outerHeight() so that you are getting the values for the current element in the loop. $(".color-menu") gets the values for an unspecified element with this class so will not work.

Trouble creating vertical parallax

I am trying to create a vertical slide show on scroll. One picture-screen glide over the next one, and then the second over the third, and so on…
HTML/CSS structure looks as following: external container has display property relative. Inside it there are several containers with images with the property fixed, so that they are all as a card deck and you pull card by card from the top.
JavaScript function should load the first pare of image-pages and follow the amount of scrolled distance changing the index of the image-page and changing the z-index of the layer (the top one: 2, the one blow: 1 and so on...)
var mansDok = []; var paklajAttal = [];
// Find all the slides containers
mansDok = document.getElementsByClassName("slaide");
// Find all the slides IDs
for(i=0; i<mansDok.length; i++) {
paklajAttal[i] = mansDok[i].id;
}
// Height of the browser window
var logAugst = document.documentElement.clientHeight;
// Start function on scrolling the contents
window.onscroll = function() {vertikSlaidrade()};
//
// Slideshow function
function vertikSlaidrade() {
var k = 0; var i = 0, winScroll;
// How far the screen been scrolled
winScroll = document.documentElement.scrollTop || document.body.scrollTop;
// Change slides while scrolling
if(winScroll <= logAugst * 1) {
document.getElementById(paklajAttal[k]).style.zIndex = "2";
document.getElementById(paklajAttal[k]).style.position = "relative";
document.getElementById(paklajAttal[k+1]).style.display = "block";
document.getElementById(paklajAttal[k+1]).style.position = "fixed";
} else if(winScroll <= logAugst * 2) {
document.getElementById(paklajAttal[k+1]).style.zIndex = "3";
document.getElementById(paklajAttal[k+1]).style.position = "relative";
document.getElementById(paklajAttal[k+2]).style.display = "block";
document.getElementById(paklajAttal[k+2]).style.position = "fixed";
} else if(winScroll <= logAugst * 2.8) {
document.getElementById(paklajAttal[k+2]).style.zIndex = "4";
document.getElementById(paklajAttal[k+2]).style.position = "relative";
document.getElementById(paklajAttal[k+3]).style.display = "block";
document.getElementById(paklajAttal[k+3]).style.position = "fixed";
} else if(winScroll > logAugst * 2.8) {
// Run reset function by the end of slides
atiestat();
}
}
// Function to reset the slides properties
function atiestat() {
for(var i=0; i<mansDok.length; i++) {
document.getElementById(paklajAttal[i]).style.zIndex = "0";
document.getElementById(paklajAttal[i]).style.position = "absolute";
document.getElementById(paklajAttal[i]).style.display = "none";
}
// Show the first pair of slides
document.getElementById(paklajAttal[0]).style.display = "block";
document.getElementById(paklajAttal[0]).style.zIndex = "2";
document.getElementById(paklajAttal[1]).style.position = "fixed";
document.getElementById(paklajAttal[1]).style.zIndex = "1";
}
* {box-sizing: border-box;}
html, body{
height: 100%;
margin: 0px;
padding: 0px;
background-color: #000;
font-size: 1em;
}
main {
position: relative;
margin: 0px;
padding: 0px;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
}
/* Page with slide */
.slaide {
position: absolute;
top: 0px;
left: 0px;
z-index: 0;
margin: 0px;
padding: 0px;
width: 100%;
display: none;
}
.slaide img {
width: 1230px; /* Doesn't work below this value !?!? */
}
/* Empty filler */
.tukss {
display: block;
margin: 0px;
padding: 0px;
height: 1000px; /* Do NOT reduce this value!!! */
}
<main>
<div class="slaide" id="lapa1" style="display: block;">
<img src="https://www.w3schools.com/howto/img_parallax.jpg">
</div>
<div class="slaide" id="lapa2">
<img src="https://www.w3schools.com/howto/img_parallax2.jpg">
</div>
<div class="slaide" id="lapa3">
<img src="https://www.w3schools.com/howto/img_parallax3.jpg">
</div>
<div class="tukss" id="tukss"></div>
</main>
May be its not the most elegant version of JS code, but everything works perfectly as I wanted. Somehow it doesn’t work if I change the image size below 1230px or to 100% and reduce the width of the browser window. (Images are from W3Schools.com)
I would appreciate if somebody could help me out with this situation.

Is there a way to check the bottom of a child div?

I'm trying to implement an Infinity scroll.
But not a window object, the target is a child div with a scroller.
Is there a way to examine the current height of a child div with JavaScript?
For example, I would like to request an event when the scroll touches at the end.
This is my template code.
<div
style="overflow-y: scroll; height:500px;"
class="scroll-content"
#scroll="onScroll"
>
Here is an example:
var listElm = document.querySelector('#infinite-list');
// Add items.
var nextItem = 1;
var loadMore = function() {
for (var i = 0; i < 10; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
loadMore();
}
});
// Initially load some items.
loadMore();
#infinite-list {
/* We need to limit the height and show a scrollbar */
width: 200px;
height: 100px;
overflow: auto;
/* Optional, only to check that it works with margin/padding */
margin: 30px;
padding: 20px;
border: 10px solid black;
}
/* Optional eye candy below: */
li {
padding: 10px;
list-style-type: none;
}
li:hover {
background: #ccc;
}
<ul id='infinite-list'>
</ul>
The following function returns, whether the user has scrolled to the bottom of a certain element:
function scrollEnd(el) {
return (el.scrollTop + el.offsetHeight >= el.scrollHeight);
}
If you add this to a scroll event listener:
element.addEventListener('scroll', () => {
if (scrollEnd(element)) {
// the user reached the end
}
})
I tried this on a textarea, should work with anything, though.

Logo cloning on navbar scroll

I have the following script:
$(function() {
var header = $(".header-nav");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 50) {
header.addClass("scrolled");
}
if (scroll > 50 && scroll < 60) {
$(".header_logo img").clone().appendTo(".header-logo");
}
if (scroll <= 50) {
header.removeClass("scrolled");
}
});
});
It's supposed to make the navbar fixed on scroll and clone the website logo to the navbar on a .header-logo empty div
But it doesn't work as expected. The logo is mass duplicated or don't appear until a top scrolling.
Is there a way to make it work as: When I scroll, the logo is cloned one time on the navbar then disappear if you go back to top page?
Thanks
Clone img outside the condition, then append or remove based on your if condition. You need to set a class to detect cloned img for removing.
$(function() {
var header = $(".header-nav");
$el = $(".header-logo img").clone().addClass('cloned');
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 50) {
header.addClass("scrolled");
} else {
header.removeClass("scrolled");
}
if (scroll > 50) {
$el.appendTo(".header-logo");
} else {
$('.cloned').remove();
}
});
});
body {
height: 1000px;
/* fake height! */
}
header.header-nav.scrolled {
position: fixed;
}
.header-nav {
background: white;
width: 100%;
min-height: 150px;
border: 1px solid gray;
}
.scrolled {
background: red;
}
.header-logo img {
height: 150px;
display: block;
margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header class="header-nav">
<div class="header-logo">
<img src="https://i.graphicmama.com/blog/wp-content/uploads/2019/10/02145410/logo-design-trends-2020-colorful-gradient-logos-example-1.gif" />
</div>
</header>

Categories