Skip to content

Instantly share code, notes, and snippets.

@wesruv
Last active December 17, 2019 18:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wesruv/36d8b9f8a2bff64f396a32ae17080a0b to your computer and use it in GitHub Desktop.
Save wesruv/36d8b9f8a2bff64f396a32ae17080a0b to your computer and use it in GitHub Desktop.
/**
* Optimized scroll handler
* @see https://developer.mozilla.org/en-US/docs/Web/Events/resize#requestAnimationFrame
*
* @example
* scroll.add(() => console.log('Resource conscious scroll callback!'));
*/
// eslint-disable-next-line no-unused-vars
export const scroll = (function() {
let callbacks = [],
running = false;
// Fired on scroll event
const onScroll = () => {
if (!running) {
running = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(runCallbacks);
}
else {
setTimeout(runCallbacks, 66);
}
}
};
// Run the callbacks
const runCallbacks = () => {
callbacks.forEach(function (callback) {
callback();
});
running = false;
};
// Adds callback to loop
const addCallback = (callback) => {
if (callback) {
callbacks.push(callback);
}
};
return {
// Public method to add additional callback
'add': function add(callback) {
if (!callbacks.length) {
document.addEventListener('scroll', onScroll, {'passive': true,});
}
addCallback(callback);
},
};
}());
// Add peek-a-book menu behavior
window.addEventListener('load', () => {
if (!$body.classList.contains('js-peek-a-book-menu')) {
// Measurement on how far direction has changed used to fire showing/hiding the menu
const peekABooDifference = 150;
let lastScrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
let scrollProgress = 0;
let scrollDirection = null;
$body.classList.add('js-peek-a-boo-menu');
// Listen to the scroll event and look for changes in direction
scroll.add(() => {
const currentScrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
const scrollDifference = currentScrollPosition - lastScrollPosition;
// If we've been scrolling down and now going up, reset progress
if (scrollProgress > 0 && scrollDifference < 0) {
scrollProgress = 0;
}
// If we've been scrolling up and now going down, reset progress
else if (scrollProgress < 0 && scrollDifference > 0) {
scrollProgress = 0;
}
// Accumulate the scrollProgress
scrollProgress += scrollDifference;
// If we've moved more than the peekaBooDifference in direction, toggle the menu state
if (scrollDirection !== 'down' && scrollProgress > peekABooDifference) {
$body.classList.remove('js-peek-a-boo-menu--scrolling-up');
$body.classList.add('js-peek-a-boo-menu--scrolling-down');
scrollDirection = 'down';
}
else if (scrollDirection !== 'up' && scrollProgress < -1 * peekABooDifference) {
scrollDirection = 'up';
$body.classList.remove('js-peek-a-boo-menu--scrolling-down');
$body.classList.add('js-peek-a-boo-menu--scrolling-up');
}
lastScrollPosition = currentScrollPosition;
});
}
});
/// Visibility has to have a different delay on default state vs open state
/// Adding mixin so transitions are managed in one place instead of 2
@mixin l-header__transitions($is-open: true) {
$visibility-delay: 0s;
@if $is-open {
visibility: visible;
}
@else {
visibility: hidden;
$visibility-delay: 0.3s;
}
// sass-lint:disable indentation
transition:
visibility 0s $visibility-delay,
transform 0.25s $cubic-bezier,
height 0.25s 0.125s $cubic-bezier;
// sass-lint:enable indentation
}
//sass-lint:disable no-mergeable-selectors
.l-header__outer-wrapper,
.l-header__primary-menu__outer-wrapper {
&,
.js-peek-a-boo-menu--scrolling-up &,
.js-show-aiche-menu[class] & {
@include l-header__transitions();
height: vr(3);
transform: none;
@include breakpoint('nav-break') {
height: vr(4);
}
}
}
.l-header__secondary-menu__outer-wrapper,
.l-header__primary-menu__outer-wrapper {
.js-has-hide-aiche-menu-button.js-hide-aiche-menu &,
.js-peek-a-boo-menu--scrolling-down & {
@include l-header__transitions(false);
transform: translate(0, -150%);
height: 0;
overflow: hidden;
}
}
// Shouldn't move around secondary menu if there's a community menu
.l-header__secondary-menu__outer-wrapper {
.js-has-hide-aiche-menu-button.js-hide-aiche-menu.js-has-community-menu &,
.js-peek-a-boo-menu--scrolling-down.js-has-community-menu & {
transform: none;
}
}
// We need to see the secondary menu if there's a community menu
.l-header__secondary-menu__outer-wrapper {
.js-has-community-menu.js-has-hide-aiche-menu-button.js-hide-aiche-menu &,
.js-show-aiche-menu[class] & {
overflow: visible;
visibility: visible;
}
}
// If there's a community AND section menu and we're scrolling down we should hide the secondary menu
.l-header__secondary-menu__outer-wrapper {
.js-has-hide-aiche-menu-button.js-hide-aiche-menu.js-has-community-menu.js-has-section-menu.js-peek-a-boo-menu--scrolling-down & {
overflow: hidden;
visibility: hidden;
}
}
//sass-lint:enable no-mergeable-selectors
// The header wrapper needs to stay visible for the secondary menu
.l-header__outer-wrapper { //sass-lint:disable-line no-mergeable-selectors
transition: height 0.25s $cubic-bezier;
.js-has-hide-aiche-menu-button.js-hide-aiche-menu & {
height: 0;
visibility: visible;
overflow: visible;
}
.js-peek-a-boo-menu--scrolling-down & {
overflow: hidden;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment