sticky-observer
A simple and easy to use sticky observer (or watcher) on HTMLElement
's in a designated container. When scrolling or resizing the window sticky-observer will tell you if an element is STICKY
, STICKY_END_OF_CONTAINER
or NORMAL
. This library does NOT include any preconfigured styling or positioning options, what happens when and how is left up to the you to configure with the help of some included helper functions.
Bring-Your-Own-Styling (BYOS)
This library was heavily inspired by sticky-js, it uses the same calculations and exhibits the same internal behaviour but due to it being completely unstyled it fits a different use case, all styling is left up to the you (BYOS).
Features
- Full control over styling/positioning/placeholder. NO magic BUT more work for you.
- Observing still works correctly with dynamic (out of control) appended container (ads)
- Written in TypeScript
- No dependencies
- Fully tested
- Small (cjs: 6.78 KB / 1.75 KB gzip) (esm: 5.88 KB / 1.59 KB gzip)
Demo
This library is in production on welt.de for a few main features.
- Sticky Page-Header (desktop only): Demo
- Sticky Video-Player (desktop only): Demo
- Sticky Social-Bar (mobile and desktop): Demo
Install
npm install @welt/sticky-observer
yarn add @welt/sticky-observer
Usage example
<div class="container"><div class="sticky-element" data-sticky-class="sticky-element--is-sticky">example</div></div>
import { StickyObserver } from '@welt/sticky-observer';
const stickyContainer = document.querySelector('.container');
const stickyElement = document.querySelector('.sticky-element');
const stickyObserver = new StickyObserver([stickyElement], stickyContainer);
stickyObserver.init();
stickyObserver.onStateChange(event => {
switch (event.nextState) {
case 'STICKY':
event.element.sticky.addStickyClass();
event.element.sticky.addPlaceholder();
break;
case 'NORMAL':
event.element.sticky.removeStickyClass();
event.element.sticky.removePlaceholder();
break;
default:
break;
}
});
stickyObserver.observe();
Options
new StickyObserver([stickyElement], stickyContainer, { offsetTop: 20, offsetBottom: 20 });
Each sticky-element can be configured with a few options via HTML [data-*]
attributes. All configuration options are optional.
<div class="container">
<div
class="sticky-element"
data-sticky-class="sticky-element--is-sticky"
data-sticky-placeholder-class="sticky-element__placeholder"
data-sticky-placeholder-auto-height="false"
data-sticky-offset-top="-20"
data-sticky-offset-bottom="-20"
>
example
</div>
</div>
API
const stickyObserver = new StickyObserver([stickyElement], stickyContainer, options);
stickyObserver.init();
stickyObserver.observe();
stickyObserver.pause();
stickyObserver.destroy();
stickyObserver.onStateChange(stickyEvent => {});
stickyObserver.onUpdate(stickyEvent => {});
stickyObserver.onResize(stickyEvent => {});
const isActive = stickyObserver.isActive();
stickyObserver.onStateChange(stickyEvent => {
const isNormal = stickyEvent.nextState === 'NORMAL';
const isSticky = stickyEvent.nextState === 'STICKY';
const isStickyEndOfContainer = stickyEvent.nextState === 'STICKY_END_OF_CONTAINER';
});
stickyObserver.onStateChange(stickyEvent => {
const prevState = stickyEvent.prevState;
const nextState = stickyEvent.nextState;
const element = stickyEvent.element;
const scrollTop = stickyEvent.scrollTop;
});
stickyObserver.onStateChange(stickyEvent => {
const sticky = stickyEvent.element.sticky;
const offsetTop = sticky.offsetTop;
const offsetBottom = sticky.offsetBottom;
const nonStickyHeight = sticky.nonStickyHeight;
const rect = sticky.rect;
const container = sticky.container;
const containerRect = sticky.container.rect;
const active = sticky.active;
const state = sticky.state;
const stickyClass = sticky.stickyClass;
const placeholderClass = sticky.placeholderClass;
const placeholderAutoHeight = sticky.placeholderAutoHeight;
sticky.addClass('some-special-class');
sticky.removeClass('some-special-class');
sticky.addStickyClass();
sticky.removeStickyClass();
sticky.addPlaceholder();
sticky.removePlaceholder();
});
Usage standalone Browser version
See Demo
Browser support
This library is transpiled to ES5 without any special / custom browser API. This means:
- in order for it to work on IE11 you must include the
classList
polyfill
Sticky-element works on all other major browsers.
Build
yarn install
yarn build
Test + Coverage
yarn test
Release
The npm and GitHub releases are triggered manually (via release-it
)
yarn publish
License
MIT