stepheniok
stepheniok

Reputation: 405

Show Div on Scroll using JavaScript

I am attempting to reveal divs as the user scrolls through the page. I am attempting to do this using javascript and css without any additional libraries.

Currently, I have a setup using jQuery that gets the job done but I am having issues finding a javascript only solution. I do not want the div to appear in a certain position, just simply as it appears in the user's viewport.

I am using opacity: 0 to hide the div, and then using $(this).animate({'opacity':'1'},500); to display.

I have been unable to find a similar javascript option that does not use a library or jQuery.

Can I achieve the code below using javascript?

A working jquery solution example is :

$(document).ready(function() {
    
    /* Every time the window is scrolled ... */
    $(window).scroll( function(){
    
        /* Check the location of each desired element */
        $('.scroll-in').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:blue; 
}

.scroll-in
{
    opacity:0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="container">
    
    <div>Show</div>
    <div>Show</div>
    <div class="scroll-in">Fade In</div>
    <div class="scroll-in">Fade In</div>
    <div class="scroll-in">Fade In</div>
    
</div>

Upvotes: 1

Views: 111

Answers (2)

gavgrif
gavgrif

Reputation: 15499

What you want to use is an intersection observer - this is a html5 method of determinig when an element is in the vieport. This can be used for funky effects - eg autoplaying a video - only when the video in in the viewport - (eg: Facebook)... or lazy loading images.

Note that you can specifiy the amount by which the element must be in the viewport for the effect to take place - this is the "threshold" in the config options.

Also note that intersection observers ARE NOT supported in IE - so you will either need to use a polyfill or have a fallback like I have provided in the example.

let paragraphs = document.querySelectorAll('p');

if ('IntersectionObserver' in window) {
  // IntersectionObserver Supported
  let config = {
        root: null,
        rootMargin: '0px',
        threshold: 1
      };

  let observer = new IntersectionObserver(onChange, config);
  paragraphs.forEach(paragraph => observer.observe(paragraph));

  function onChange(changes, observer) {
    changes.forEach(change => {
      if (change.intersectionRatio > 0) {
        // Stop watching and load the image
        showParagraph(change.target);
        observer.unobserve(change.target);
      }
    });
  }

} else {
  // IntersectionObserver NOT Supported
  paragraphs.forEach(paragraph => showParagraph(paragraph));
}

function showParagraph(paragraph) {
  paragraph.classList.add('fade-in');
}
p {
  opacity: 0
}

.fade-in {
          animation-name: fadeIn;
          animation-duration: 1000ms;
          animation-timing-function: cubic-bezier(0, 0, 0.4, 1);
          animation-fill-mode: forwards;
}


@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
<h2>Scroll me to see paragraphs appear when the are fully within the viewport </h2>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.<p>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.<p>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.<p>

<p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

<p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

<p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.<p>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.<p>

<p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

Upvotes: 2

ray
ray

Reputation: 27245

You could accomplish this with plain javascript using an IntersectionObserver. Here's a quick skeletal example:

const callback = (entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      if (entry.intersectionRatio > .5) {
        entry.target.classList.add('active');
      }
      else {
        entry.target.classList.remove('active');
      }
    }
  });
}

const observer = new IntersectionObserver(callback, {threshold: 1});
document.querySelectorAll('div').forEach(d => observer.observe(d));
div {
  background: bisque;
  min-height: 100px;
  width: 50%;
  margin-bottom: 0.5rem;
  opacity: 0;
  transition: all 0.5s ease-out;
}


div.active {
  background: tomato;
  width: 100%;
  opacity: 1;
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

Upvotes: 2

Related Questions