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:
Does anyone have any idea how this can be implemented?
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:
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
});
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);
}
});
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.
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");
});
}
});
}
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();
});
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>
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>