简体   繁体   中英

How to fade in / fade out a button on scrolling down / up respectively

I am working on my portfolio website and I am a complete beginner in Javascript.

I would like a button which has its position fixed, to slowly fade in when I scroll down (suppose when I scroll to >=20px from the top of the document, it should fade in) and when I scroll back up to the original position, it should gradually fade out .

I have already tried my hand and written a code for this. It is working perfectly when you scroll down and up. But when you quickly scroll and stop scrolling in the mid-way, it behaves pretty abnormally (suddenly appears or disappears).

HTML :

<div class="a_large_page">
    <div class="enclose bordar black" id="bottomtoup">hello</div>
</div>

JS :

mybutton = document.getElementById("bottomtoup")

// initially, the button stays hidden
visible = false

// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {
  scrollFunction()
};

function scrollFunction() {
  if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
    if (!visible) { // if the button is not visible,
      unfade(mybutton); // function to gradually fadein button
      visible = true; // button is visible so, set visible = false to true.
    }

  } else {

    if (visible) { // if the button is visible,
      fade(mybutton); // function to gradually fadeout button
      visible = false; // set visible = true back to false
    }


  }
}


function unfade(element) {
  var op = 0.1; // initial opacity
  element.style.display = 'flex';
  var timer = setInterval(function() {
    if (op >= 1) {
      clearInterval(timer);
    }
    element.style.opacity = op;
    element.style.filter = 'alpha(opacity=' + op * 100 + ")";
    op += op * 0.1;
  }, 10);
}


function fade(element) {
  var op = 1; // initial opacity
  var timer = setInterval(function() {
    if (op <= 0.1) {
      clearInterval(timer);
      element.style.display = 'none';
    }
    element.style.opacity = op;
    element.style.filter = 'alpha(opacity=' + op * 100 + ")";
    op -= op * 0.1;
  }, 50);
}

 

Here is the fiddle: https://jsfiddle.net/P0intMaN/Lmp6u5ft/23/

My code is pretty substandard for sure. That's why it is behaving in this way. Hence, I am looking for an efficient way to achieve this. I have seen people making use of JQuery to do this, but I don't know JQuery at all. So, it would be much appreciated if the code is in pure JS .

There is no need to have so much JS when you can do in so little:

If you feel to change the timing of

 // Set a function onscroll - this will activate if the user scrolls window.onscroll = function() { // Set the height to check for var appear = 20 if (window.pageYOffset >= appear) { // If more show the element document.getElementById("bottomtop").style.opacity = '1' document.getElementById("bottomtop").style.pointerEvents = 'all' } else { // Else hide it document.getElementById("bottomtop").style.opacity = '0' document.getElementById("bottomtop").style.pointerEvents = 'none' } }
 .a_large_page{ background-color: gray; height: 2000px; } .enclose{ height: 40px; width: 40px; position:fixed; margin-right: 20px; margin-bottom: 20px; right:0; bottom:0; pointer-events:none; opacity:0; justify-content: center; align-items: center; color:white; /* This determines how fast animation takes place, you can change it as per your choice. */ transition:all 0.6s; } .enclose:hover{ cursor: pointer; }
 <div class="a_large_page"> <div class="enclose bordar black" id="bottomtop">hello</div> </div>

I've changed your code and removed setInterval usage. This can be solved with it but may be harder to understand for newer coders.

There are also flags to keep track of whether you are currently fading or unfading to ensure you do not stack or "overlap" timeout/intervals.

mybutton = document.getElementById("bottomtoup")

// initially, the button stays hidden
var visible = false

// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {
  scrollFunction()
};

function scrollFunction() {
    var threshold = 20;
    var below_threshold = document.body.scrollTop > threshold || document.documentElement.scrollTop > threshold;
  
  if (below_threshold) {
    if (!visible) { // if the button is not visible,
      unfade(mybutton); // function to gradually fadein button
    }
    
    return;
  }

  if (visible) { // if the button is visible,
    fade(mybutton); // function to gradually fadeout button
  }
}

var current_opacity = 0.1;
var is_unfading = false;
var is_fading = false;

function unfade(element) {
    if(!visible){
    element.style.display = 'flex';
    visible = true;
  }
  
  is_fading = false;
  is_unfading = true;
  
  unfade_step(element);
}

function unfade_step(element){
    element.style.opacity = current_opacity;
    element.style.filter = 'alpha(opacity=' + current_opacity * 100 + ")";
    
    if (current_opacity >= 1){
        // end
      is_unfading = false;
      current_opacity = 1;
        return;
    }
    
    current_opacity += 0.01;
    if(is_unfading){
      setTimeout(function(){
        unfade_step(element);
      }, 10);
    }
}

function fade(element) {
    if(!visible){
    return;
  }
  
  is_fading = true;
  is_unfading = false;
  
  fade_step(element);
}


function fade_step(element) {
    element.style.opacity = current_opacity;
    element.style.filter = 'alpha(opacity=' + current_opacity * 100 + ")";
    
    if (current_opacity <= 0.001){
        // end
      is_fading = false;
      visible = false;
      current_opacity = 0.1;
        element.style.display = 'none';
        return;
    }
    
    current_opacity -= 0.01;
    if(is_fading){
      setTimeout(function(){
        fade_step(element);
      }, 10);
    }
}

There is no need to sense the scroll event in more modern browsers as you can use IntersetionObserver to tell you when scrolling has gone past 20px;

You can do this by placing a tiny element at the top of the page with height 20px. You then ask the system to tell you when this has gone out of, or comes back into, the viewport. At these points you can set the opacity of the Hello to 1 or 0 as appropriate.

The extra bonus is that you get rid of a lot of code and there isn't the possible clash between set intervals as we use transition on the opacity to do the gradual fade in/out.

 // See MDN for more info on IntersectioObserver let callback = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { mybutton.style.opacity = 0; } else { mybutton.style.opacity = 1; } }); }; const mybutton = document.getElementById("bottomtoup") const observer = new IntersectionObserver(callback); const observed = document.getElementById("observed"); observer.observe(observed);
 .a_large_page { background-color: gray; height: 2000px; position: relative; } #observed { position: absolute; top: 0; left: 0; height: 20px; width: 10px; z-index: -999; } .enclose { height: 40px; width: 40px; position: fixed; margin-right: 20px; margin-bottom: 20px; right: 0; bottom: 0; justify-content: center; align-items: center; color: white; opacity: 0; transition: opacity 1s linear; }
 <div class="a_large_page"> <div id="observed"></div> <div class="enclose bordar black" id="bottomtoup">hello</div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM