Search code examples
javascriptjqueryhtmlfadeoutslidedown

How can I fadeOut a div when I scroll down to the hole div, It will not show again


I am looking to implement a feature in which a notification displays via slideDown at the top of the page on a button (or other element) click, and then hides via fadeOut when it is scrolled out of view. This functionality is similar to what happens when clicking "How It Works" on airbnb's website.

For clarity, the following is the functionality that I am looking for:

  1. Click a specified element to make the notification display
  2. Notification slides into view at the top of the page and window automatically scrolls to the top
  3. User scrolls down the page and the notification element fades out as soon as it is scrolled out of view

Does anyone have any idea how this can be implemented?


Solution

  • The implementation they use is pretty long and has a lot of functions returning functions, but the following is a quick pseudo-code description of what you need to do:

    1. Create a click handler for the element you want to use as your "show button" that shows your "notification" when clicked. Note that my implementation jumps to the top of the page. In your implementation, you should change this to the smooth scrolling technique of your choice. UPDATE: I checked against Airbnb's site again and even without the smooth scrolling my implementation visually functions the same as theirs.

      var $notification = $(".notification");
      
      $(document).on("click", ".show-button", function() {
          $notification.slideDown(); //can use whatever effect you want here, or just .show()
          window.scrollTo(0, 0); //scroll to top of page
      });
      
    2. Next, create a scroll handler for the window that checks to see if the page has been scrolled down below the height of the "notification" (in other words, check to see if the notification is no longer in view). If it is not in view anymore, hide the element and update the scroll position so the page doesn't jump. Note that with my implementation, the page may jump in slower browsers because I'm not using smooth scrolling. However, when you add smooth scrolling the effect will look natural.

      $(window).on("scroll", function() {
          var notificationHeight = $notification.outerHeight(); //may be able to cache this or calculate outside the handler for reuse, depending on implementation
          var currentScrollY = $(window).scrollTop();
      
          if (currentScrollY > notificationHeight) {
              $notification.hide(); 
      
              //update the scroll browser scroll position
              var updatedScrollY = currentScrollY - notificationHeight;
              window.scrollTo(window.scrollX, updatedScrollY);
          }
      });
      
    3. If we are looking to use an animation/effect to hide the "notification," then we need to update our scroll handler from the above. Looking at the current code, notice that we use $notification.hide() which instantly removes the element from the document. As such, the space consumed by the notification is not included when we compute the updated scroll position. However, if you use an animation/effect, like .fadeOut, the element's display property is not set to none until the animation COMPLETES, though the script execution continues immediately after the animation BEGINS (i.e. immediately after it is called). As such, the new scroll position will be calculated and applied before the notification is removed from the flow, causing the page to appear to jump to the top, with the notification in full or nearly full view. In order to get around this, we need to hold off on the execution of the the code to update the scroll position until the animation/effect finishes. We can do this easily moving the code for updating the scroll position into the animation/effect method's callback.

      $(window).on("scroll", function() {
          var notificationHeight = $notification.outerHeight(); //may be able to cache this or calculate outside the handler for reuse, depending on implementation
          var currentScrollY = $(window).scrollTop();
      
          if (currentScrollY > notificationHeight) {
              //can use whatever effect you want, but must pass scroll position update code in callback to prevent page jump, if not using .hide()
              $notification.fadeOut(function () {
                //update the scroll browser scroll position
                var updatedScrollY = currentScrollY - notificationHeight;
                window.scrollTo(window.scrollX, updatedScrollY);
              });
          }
      });
      

      NOTE: Since we cannot see the element, we shouldn't be using an animation/effect, like fadeOut, to hide the notification. Adding the effect would merely add unnecessary overhead, since the element is not in view when it is hidden. However, I have included this step because the OP specifically mentioned using fadeOut for hiding the notification. I will include examples for both in the demo.

    4. Since I'm a fan of performance and we don't need handle the scroll event of window unless the "notification" is actually being shown, let's move our scroll handler binding into a function, and add a namespace and .off call so that we can unbind it without affecting other handlers.

      //binds the scroll handler we created in step 2 to the window
      function bindScrollHandlerForNotification() {
          $(window).on("scroll.checkHideNotification", function() {
              var notificationHeight = $notification.outerHeight(); //may be able to cache this or calculate outside the handler for reuse, depending on implementation
              var currentScrollY = $(window).scrollTop();
      
              if (currentScrollY > notificationHeight) {
                  //can use whatever effect you want, but must pass scroll position update code in callback to prevent page jump, if not using .hide()
                  $notification.fadeOut(function() {
                      //update the scroll browser scroll position
                      var updatedScrollY = currentScrollY - notificationHeight;
                      window.scrollTo(window.scrollX, updatedScrollY);
      
                      //unbind the handler since the notification is hidden
                      $(window).off("scroll.checkHideNotification");
                  });
              }
          });
      }
      
    5. Now that we have a function to bind our handler, let's update the click handler from step 1 to call the function to bind our scroll handler.

      $(document).on("click", ".show-button", function() {
          $notification.slideDown(); //can use whatever effect you want here, or just .show()
          window.scrollTo(0, 0); //scroll to top of page
          bindScrollHandlerForNotification();
      });
      


    FINAL IMPLEMENTATIONS AND DEMOS

    Using .fadeOut() to hide notification

    var $notification = $(".notification");
    
    //listen for our show button to be clicked
    $(document).on("click", ".show-button", function() {
      $notification.slideDown(); //can use whatever effect you want here, or just .show()
      window.scrollTo(0, 0); //scroll to top of page
      bindScrollHandlerForNotification();
    });
    
    //binds the scroll handler we created in step 2 to the window
    function bindScrollHandlerForNotification() {
      $(window).on("scroll.checkHideNotification", function() {
        var notificationHeight = $notification.outerHeight(); //may be able to cache this or calculate outside the handler for reuse, depending on implementation
        var currentScrollY = $(window).scrollTop();
    
        if (currentScrollY > notificationHeight) {
          //can use whatever effect you want, but must pass scroll position update code in callback to prevent page jump, if not using .hide()
          $notification.fadeOut(function() {
              //update the scroll browser scroll position
              var updatedScrollY = currentScrollY - notificationHeight;
              window.scrollTo(window.scrollX, updatedScrollY);
    
              //unbind the handler since the notification is hidden
              $(window).off("scroll.checkHideNotification");
          });
        }
      });
    };
    .page-container {
      height: 5000px;
    }
    .notification {
      display: none;
      padding: 75px;
      border-bottom: 1px solid white;
      background: #009afd;
      text-align: center;
      font-size: 30px;
      font-weight: bold;
      font-family: arial, helvetica, sans-serif;
    }
    .main-content {
      width: 75%;
      height: 100%;
      margin: 0 auto;
      border-left: 2px solid rgb(200, 200, 200);
      border-right: 2px solid rgb(200, 200, 200);
      padding: 20px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <div class="page-container">
      <div class="notification"><span class="notification-content">Test Notification</span>
      </div>
      <div class="main-content">
        <div class="content-block">
          <button type="button" class="show-button">Show Notification</button>
        </div>
      </div>
    </div>


    Using .hide() to hide notification

    var $notification = $(".notification");
    
    //listen for our show button to be clicked
    $(document).on("click", ".show-button", function() {
      $notification.slideDown(); //can use whatever effect you want here, or just .show()
      window.scrollTo(0, 0); //scroll to top of page
      bindScrollHandlerForNotification();
    });
    
    //binds the scroll handler we created in step 2 to the window
    function bindScrollHandlerForNotification() {
      $(window).on("scroll.checkHideNotification", function() {
        var notificationHeight = $notification.outerHeight(); //may be able to cache this or calculate outside the handler for reuse, depending on implementation
        var currentScrollY = $(window).scrollTop();
    
        if (currentScrollY > notificationHeight) {
          //can use whatever effect you want, but must pass scroll position update code in callback to prevent page jump, if not using .hide()
          $notification.hide();
          
          //update the scroll browser scroll position
          var updatedScrollY = currentScrollY - notificationHeight;
          window.scrollTo(window.scrollX, updatedScrollY);
    
          //unbind the handler since the notification is hidden
          $(window).off("scroll.checkHideNotification");
        }
      });
    };
    .page-container {
      height: 5000px;
    }
    .notification {
      display: none;
      padding: 75px;
      border-bottom: 1px solid white;
      background: #009afd;
      text-align: center;
      font-size: 30px;
      font-weight: bold;
      font-family: arial, helvetica, sans-serif;
    }
    .main-content {
      width: 75%;
      height: 100%;
      margin: 0 auto;
      border-left: 2px solid rgb(200, 200, 200);
      border-right: 2px solid rgb(200, 200, 200);
      padding: 20px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <div class="page-container">
      <div class="notification"><span class="notification-content">Test Notification</span>
      </div>
      <div class="main-content">
        <div class="content-block">
          <button type="button" class="show-button">Show Notification</button>
        </div>
      </div>
    </div>