Detecting end of scroll in a div - javascript

I have a dynamic website with many blog posts. I want to load just four posts at first and load another four when scrolled to end. I know how to handle it on the backend, but I am having problem on the frontend. I have set the height of html and body to 100%, due to which scroll events on the window didn't work. As a workaround, I decided to use a single div to detect the scroll. I added scroll event on the div, and it worked fine. But when I tried to detect the end of scroll on the div, the code executed at the beginning of the page load before performing any scrolls. The code I used is:
if (element.scrollHeight - element.scrollTop === element.clientHeight){
alert("End");
}
How do I make the alert to appear only after the div has been scrolled to the end instead at the begining?

You can use element.scrollTop + element.offsetHeight>= element.scrollHeight to detect scroll end.
Update:
Also adding a condition so that it won't fire when scrolling upwards.
For more on upward scroll condition,you can check this link.
const element = document.getElementById('element');
let lastScrollTop = 0;
element.onscroll = (e)=>{
if (element.scrollTop < lastScrollTop){
// upscroll
return;
}
lastScrollTop = element.scrollTop <= 0 ? 0 : element.scrollTop;
if (element.scrollTop + element.offsetHeight>= element.scrollHeight ){
console.log("End");
}
}
#element{
background:red;
max-height:300px;
overflow:scroll;
}
.item{
height:100px;
}
<div id="element">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>

Answer for year 2023.
Now we have scrollend event.
Tested on chromium 108, firefox 109
Example:
const output = document.querySelector("p#output");
document.addEventListener("scrollend", (event) => {
output.innerHTML = `Document scrollend event fired!`;
});
According to mdn docs:
The scrollend event fires when the document view has completed scrolling.
Scrolling is considered completed when the scroll position has no more pending updates and
the user has completed their gesture.
Know more at mdn : Document: scrollend event

element.scrollTop + element.offsetHeight >= element.scrollTopMax
I mainly use this as a condition

Related

Making on-scroll style changes using vanilla js

I want remove .bg-light from nav element at 400px and more scrolls
<nav id="my-nav" class="bg-light navbar text-info"> change my background color</nav>
I know it's an easy task with jQuery but is it possible to do it with vanilla js?
Thanks for spending time on my question I will be glad to see opinion
First, we start by grabbing the "nav" element using the ID.
Then setting our Y-axis's offset.
Attach a listener to the window object.
On scroll, compare the current position to our desired offset.
const navBar = document.getElementById("my-nav");
const offset = 400;
window.addEventListener("scroll", () => {
if (window.scrollY >= offset){
navBar.classList.remove("bg-light")
} else {
navBar.classList.add("bg-light")
}
})
Yes, its possible with Vanilla JavaScript, use the "scroll" event handler to get the info. As the users moves through the site it will return the Y axis position in pixels. By using an if statement remove or add the bg-light class, like so:
let nav = document.getElementById("my-nav");
window.addEventListener("scroll", (e) => {
if(this.scrollY > 400){ nav.classList.remove('bg-light') }
else{
nav.classList.add('bg-light')
}
});
*{padding:5px}
html{height:3000px;font-size:20px}
.bg-light{background-color: #F8F8F8!important; color:black!important;}
.navbar{position:fixed;background-color:blue; color:white;}
<nav id="my-nav" class="bg-light navbar text-info"> Change my background color at scrollY 400px</nav>

Javascript/React onClick scroll set amount down/up

I got a problem figuring out how to make a button onClick scroll down for example 30px per click.
say i got two divs with icons like this
<div className="info-container">
<div className="scroll-icon-container" onClick={scrollUp(30)}>
<ScrollUpIcon />
</div>
<div className="scroll-icon-container" onClick={scrollDown(30)}>
<ScrollDownIcon />
</div>
<p>"Huge amount of text that will need scrolling"</p>
</div>
Then two functions like
scrollUp(number: amountToScroll){
//Scroll the "info-container" up amountToScroll pixels
}
scrollDown(number: amountToScroll){
//Scroll the "info-container" down amountToScroll pixels
}
All i could find so far is either in jquery or how to make it scroll to a specific element but i am looking for a set amount to scroll down in pixels % or whatever works.
First of all you can either define a variable or state for maintaining the scroll position.
Let us take state as scrollPosition and initialize it to 0.
Now in the scrollUp function:
scrollUp(amountToScroll){
this.setState({
scrollPosition : this.state.scrollPosition + amountToScroll
})
window.scrollTo(0, this.state.scrollPosition)
}
Now in scrollDown function:
scrollDown(amountToScroll){
this.setState({
scrollPosition : this.state.scrollPosition - amountToScroll
})
window.scrollTo(0, this.state.scrollPosition)
}
Use window.scrollBy( pixelsToScrollRight, pixelsToScrollDown ) method.
So instead of scrollUp() and scrollDown() methods you can have something like this:
scroll(number: amountToScroll){
//amount to scroll is negative to scroll up
window.scrollBy(0 , amountToScroll)
}
If you want to look at scrolling inside a div: How to scroll to an element inside a div?

Fading in divs in html using javascript

In my project I want to fade in divs in html and I am using the following code
$(document).ready(function() {
/* Every time the window is scrolled ... */
$(window).scroll( function(){
/* Check the location of each desired element */
$('.hideme').each( function(i){
var bottom_of_object = $(this).offset().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
/* If the object is completely visible in the window, fade it it */
if( bottom_of_window > bottom_of_object ){
$(this).animate({'opacity':'1'},500);
}
});
});
});
#container {
height:2000px;
}
#container div {
margin:50px;
padding:50px;
background-color:lightgreen;
}
.hideme {
opacity:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdn.jsdelivr.net/g/jquery.fullpage#2.5.9(jquery.fullPage.min.js+vendors/jquery.easings.min.js+vendors/jquery.slimscroll.min.js)"></script>
<link href="https://cdn.jsdelivr.net/jquery.fullpage/2.5.9/jquery.fullPage.min.css" rel="stylesheet" />
<div id="container">
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div class="hideme">Fade In</div>
<div class="hideme">Fade In</div>
<div class="hideme">Fade In</div>
<div class="hideme">Fade In</div>
<div class="hideme">Fade In</div>
</div>
which can be found at this JS Fiddle
In the project I also use the javascript code for
$(document).ready(function() {
$('#fullpage').fullpage();
});
which basically makes the scrolling better, details at https://github.com/alvarotrigo/fullPage.js/
The problem: Because of the full page code the fading in function does not enter the scroll if condition.
I think you're looking for something like this JS Fiddle 1
JS:
//initialize
var winHeight = $(window).height(),
sections = $('.sections'),
currentSlide = 0;
$('html, body').animate({scrollTop: 0}, 0);
//hide elements not in the view as the page load for the first time
sections.each(function() {
if ($(this).offset().top > winHeight - 5) {
$(this).fadeOut(0);
}
});
//show elements on scroll
$(window).scroll(function(event) {
// retrieve the window scroll position, and fade in the 2nd next section
// that its offset top value is less than the scroll
scrollPos = $(window).scrollTop();
if (scrollPos >= currentSlide * winHeight) {
nextSlide = currentSlide + 2;
$('#sec-' + nextSlide).fadeIn();
// as long as current slide is still in range of the number of sections
// we increase it by one.
if (currentSlide <= sections.length) {
currentSlide++;
}
}
});
----------
Update:
Upon a comment by the OP "I want the divs within sections to fade in on scroll not the section div but the ones inside it as there are multiple", all what we need to do is to change this line $(this).fadeOut(0); to this $(this).children().fadeOut(0); and then this line:
$('#sec-' + nextSlide).fadeIn(); to this $('#sec-' + nextSlide).children().fadeIn(1500);
and now, instead of the section itself, we're fading in and out all children of that section.
JS Fiddle 2
I'm surprised the previous answer got so many upvotes when the scroll event doesn't even get fired when using fullPage.js :D
The solution for your problem is detailed in the fullPage.js FAQs.
Which is basically using the fullPage.js option scrollbar:true or autoScrolling:false. This way the scroll event will get fired.
If you still want to use your fading effects when changing from one section to another, the proper solution is making use of fullPage.js callbacks or fullpage.js state classes to fire the animations. That can be done using javascript or plain css 3.
Check an example on how to use css3 animations in combination with the fullpage.js state classes on this video tutorial.

Detecting if a scrollable DIV has reached the bottom

I have a <div> with overflow: scroll; applied, that I want to detect when it's being scrolled, and trigger just as it hits 5% of it's total height remaining.
JSBin - Currently I'm failing to trigger when it hits the bottom of the page.
<div style="height:50%;overflow:scroll;">
<b style="height:5000px;display:block;"></b>
</div>
$('div').on('scroll', function(){
if($(window).scrollTop() + $('div').height() == $('div').height()) {
console.log("bottom of page");
}
});
The window is not scrollable in your example, the div is. This results in the div being the element to look for when checking the scrollTop() function. Also, the summation here is greater than your b element (which you need to check for) and not equal. So changing the lines as follows the code executes as you've expected:
$('div').on('scroll', function(){
if($("div").scrollTop() + $('div').height() > $('b').height()) {
console.log("bottom of page");
}
});

Multiple ID in getElementById

I've found a great tutorial to detach a navigation from the page to keep it static when you scroll using Javascript (http://code.stephenmorley.org/javascript/detachable-navigation/).
However, I'd like to implement this on more than one nav div.
I assume it's adding another class name to document.getElementById('navigation').className but I can't get the right syntax
Here is the code:
/* Handles the page being scrolled by ensuring the navigation is always in
* view.*/
function handleScroll(){
// check that this is a relatively modern browser
if (window.XMLHttpRequest){
// determine the distance scrolled down the page
var offset = window.pageYOffset
? window.pageYOffset
: document.documentElement.scrollTop;
// set the appropriate class on the navigation
document.getElementById('navigation').className =
(offset > 104 ? 'fixed' : '');
}
}
// add the scroll event listener
if (window.addEventListener){
window.addEventListener('scroll', handleScroll, false);
}else{
window.attachEvent('onscroll', handleScroll);
}
You will have to call getElementById() for each ID. The Method is only designed to get exactly one element (or zero, if the ID isn't found).
Assuming, you have two navigation divs, left and right, like this:
<div id="navigationLeft">
<ul>
<!-- Navigation entries -->
</ul>
</div>
<!-- Maybe some content or whatever? -->
<div id="navigationRight">
<ul>
<!-- Navigation entries -->
</ul>
</div>
Then your Javascript line in question would look like this:
// set the appropriate class on the navigation
document.getElementById('navigationLeft').className = (offset > 104 ? 'fixed' : '');
document.getElementById('navigationRight').className = (offset > 104 ? 'fixed' : '');
// or, shorter but less readable (i think)
document.getElementById('navigationLeft').className
= document.getElementById('navigationRight').className
= (offset > 104 ? 'fixed' : '');
If this does not yet answer your question, please feel free to add some relevant HTML-Code to your question.
[Update: Example]
This is not recommended you should replace id with classes and use that in a loop to set the value:
HTML:
<div class="navigation">
<p>test 1</p>
</div>
<div class="navigation">
<p>test 2</p>
</div>
Javascript:
divs = document.getElementsByClassName('navigation');
for(i = 0; i < divs.length; i++) {
var div = divs[i];
var divClassName = div.className;
if(divClassName.indexOf('fixed') != -1 && offset > 104) {
divClassName.replace(' fixed','');
} else {
divClassName += ' fixed';
}
}
I think that will do the trick :-)
Greetings!
Gonzalo G.
you shouldnt have multiple items on a page with the same ID, ID's are meant to be unique...if you want to capture multiple items you should use:
<div class="navigation"></div>
var nodes = document.getElementsByClassName('navigation')
...if not using jquery, otherwise do something like
var nodes = $('.navigation')
which will get you yor nav bars, then check to see if that node is also "fixed" ( a node can have more than one css class )
(nodes[i].indexOf("navigation") >= 0)
if using jquery, you can use .hasClass('fixed') )
nodes[i].hasClass('fixed')
...your current problem is that it cant add className to navigation because there are two of them and youre not specifying which one you'd like to use.
If you want this to happen in two navigation div's, consider putting them both into one div and call it nav and set a style on it (this depends on your design)
All id's on an element must be unique.
One solution so that you can do a simple change would be to change the CSS file to something like this:
.navigation{
position:absolute;
top:120px;
left:0;
}
.navigationFixed{
position:fixed;
top:16px;
}
And define the Div's vis this:
<div class="navigation">
<!-- your navigation code -->
</div>
And then edit the JavaScript to something along the lines of this:
/* Handles the page being scrolled by ensuring the navigation is always in
* view.
*/
function handleScroll(){
// check that this is a relatively modern browser
if (window.XMLHttpRequest){
divs = document.getElementsByClassName('navigation');
for(i = 0; i < divs.length; i++) {
// determine the distance scrolled down the page
var offset = window.pageYOffset
? window.pageYOffset
: document.documentElement.scrollTop;
divs[i].className =
(offset > 104 ? 'navigationFixed' : 'navigation');
}
}
}
// add the scroll event listener
if (window.addEventListener){
window.addEventListener('scroll', handleScroll, false);
}else{
window.attachEvent('onscroll', handleScroll);
}

Categories