1.4.0 • Published 5 years ago

scroll-reaction v1.4.0

Weekly downloads
4
License
MIT
Repository
github
Last release
5 years ago

Scroll-Reaction.js

Performant, dependency free and fully customizable scroll effects

Highlight the current section in your navigation, hide your header on scroll or let elements appear with beautiful CSS transitions – it’s easy with Scroll-Reaction.js.

Scroll-Reaction.js adds data attributes to elements when other elements become visible (after scrolling). You just link them together. It is simple, but it makes many things possible.

Why do I need it?

Let’s face it: We develop a lot of single page websites these days. Most of them need some sort of navigation, where the current section is highlighted. And they need smooth scrolling and animations, too.

It can be a tedious task: It involves listening to scroll and resize events, updating DOM elements and thinking about many stress cases (e.g. unreachable sections, keyboard accessibility, browser support, reduced motion media query). And did I mention the perfomance issues of an un-throttled callback function?

You probably don’t want to think about that, and you don’t want to pull in a huge library either. Introducing Scroll-Reaction.js – a tiny JavaScript library for ridiculously easy scroll effects.

Some benefits:

  • ready to use in less than a minute
  • very small file size (~ 1KB gzipped)
  • dependency free
  • optimized for performance
  • fully customizable, if you need it

Table of contents

  1. Installation
  2. Getting started
  3. Examples
  4. Options
  5. API and Events
  6. Help and browser support
  7. License

Installation

Option 1: Browser

Download it here: scroll-reaction.min.js

Include the basic version in your HTML file:

<script src="scroll-reaction.min.js"></script>

Read Getting started, scroll and party! 🎉

Option 2: Node.js (build tools)

Use npm to install Scroll-Reaction.js in your project:

$ npm install scroll-reaction

Include it:

const ScrollReaction = require("scroll-reaction");

Done! 📦


Please note: Most modern browsers still don’t support scroll behavior for native smooth scrolling. The default version of Scroll-Reaction.js doesn’t include a polyfill. If you need a polyfill, you can use the file scroll-reaction-with-polyfill.min.js.

Getting started

Let’s say we’re building a simple website with 3 sections:

<section id="section-1">
  ...
</section>
<section id="section-2">
  ...
</section>
<section id="section-3">
  ...
</section>

We want to add a navigation, where the link to the current section is highlighted. For that purpose we add some markup with Scroll-Reaction.js-specific data attributes:

<nav>
  <a href="#section-1" data-scroll-reaction>Section 1</a>
  <a href="#section-2" data-scroll-reaction>Section 2</a>
  <a href="#section-3" data-scroll-reaction>Section 3</a>
</nav>

Afterwards we include Scroll-Reaction.js in the HTML file before </body> and initialize it:

<script src="scroll-reaction.min.js"></script>
<script>
  var reaction = new ScrollReaction();
</script>

Done! 😮

Now, if a user scrolls to one of our sections, the corresponding anchor tag receives a new attribute: data-scroll-active. Additionally, if the user clicks on a link, the browser will scroll smoothly to the destination.

It’s entirely up to you to add styling. Scroll-Reaction.js only assigns attributes. You can use an attribute selector to assign CSS styles to active links:

a[data-scroll-active] {
  /* Styles for links to currently visible section */
}

Examples

“Scroll to top” link

You can easily create a “scroll to top” link with smooth scrolling. Just add a data attribute:

<a href="#" data-scroll-reaction>Beam me up!</a>

Scroll-Reaction.js is smart enough to read the href attribute and send the user to the right location. It even updates the URL with the correct hash.

Animated appearance of elements

Scroll-Reaction.js works well with links, but it can handle any kind of HTML element. You want to animate the appearance of an element? Do it:

<section id="example" data-scroll-reaction="example">
  Animate me!
</section>

If there is no href attribute, you have to assign a value to the data attribute. Scroll-Reaction.js finds the element with the given ID (emitter element). It then assigns the new attribute data-scroll-active to the element with the data-scroll-reaction attribute (listener element), if the user reaches the position of the emitter element. In this example <section> is both emitter and listener element.

Include Scroll-Reaction.js:

<script src="scroll-reaction.min.js"></script>
<script>
  var reaction = new ScrollReaction({
    // Never remove attributes
    rewind: false,
    // Animate all visible elements
    multiple: true
  });
</script>

And add some nice CSS transitions:

#example[data-scroll-active] {
  transition: all 1s ease;
  transform: rotate(180deg);
}

It’s easy! 🎊

Hide your header on scroll

Maybe you have a fixed header like this:

<header id="example">Hide me!</header>

You can use the Scroll-Reaction.js API to hide it after a certain amount of scrolling:

<script src="scroll-reaction.min.js"></script>
<script>
  // Get the header
  var header = document.getElementById("example");

  // Initialize Scroll Reaction
  var reaction = new ScrollReaction();

  reaction.on("update", function() {
    // Has the user scrolled too far?
    if (this.position > 999) {
      // Add a class to hide the header
      // You can easily animate it with CSS transitions
      header.classList.add("is-hidden");
    }
  });
</script>

Don’t forget to add some CSS for smooth transitions. ✨

Even more examples

Be sure to have a look at the examples folder to learn all about Scroll-Reaction.js.

Options

Scroll-Reaction.js is fully customizable, if you need it.

You can pass a config object to the constructor function. These are the default values:

var reaction = new ScrollReaction({
  /**
   * Explanation of terms:
   *
   * Listener elements can be registered
   * by adding custom data attributes, e.g.
   * <a href="#section-1" data-scroll-reaction>...</a>
   *
   * Emitter elements are linked to listener elements
   * Usually the href attribute of a listener element should
   * match the id of the emitter element, e.g.
   * <section id="section-1">...</section>
   *
   * Scroll-Reaction.js works well with links,
   * but it can handle any kind of HTML element.
   * If there is no href attribute, you have to assign
   * a value to the data attribute, e.g.
   * <h1 data-scroll-reaction="section-1">...</h1>
   */

  /**
   * This attribute is used to find listener elements.
   * By default the href page anchor (e.g. href="#...")
   * will be used to identify emitter elements.
   * However, you can set this attribute to a valid id,
   * if no href attribute exists.
   * @type {String}
   *
   * @example
   * <a href="#section-1" data-scroll-reaction>...</a>
   * <section id="section-1">...</section>
   */
  attribute: "data-scroll-reaction",

  /**
   * This attribute will be added to listener elements,
   * if the user reaches an emitter element.
   * If you pass an empty string or explicity set it to false,
   * no attribute will be added.
   * It’s entirely up to you to add styling.
   * @type {String}
   *
   * @example
   * a[data-scroll-active] { ... }
   */
  attributeCurrent: "data-scroll-active",

  /**
   * By default only one emitter element can be active at any given time.
   * This is always the latest element, which has been reached by the user.
   * If this option is set to true, every visible emitter element will become active.
   * @type {Boolean}
   */
  multiple: false,

  /**
   * Top offset for detecting emitter elements inside the viewport.
   * If your listener element should receive its attribute earlier,
   * you should pass a (much) higher value.
   * If you want the offset to always match the height of an element,
   * you can pass a function, that calculates the offset and returns a number.
   * @type {Number|function}
   */
  offsetTop: 5,

  /**
   * Bottom offset for detecting emitter elements inside the viewport.
   * If your listener element should receive its attribute earlier,
   * you should pass a (much) higher value.
   * If you want the offset to always match the height of an element,
   * you can pass a function, that calculates the offset and returns a number.
   * This value has no effect, if the multiple config option is set to false.
   * @type {Number|function}
   */
  offsetBottom: 5,

  /**
   * If the user scrolls past an emitter element,
   * all linked listener elements will get a new attribute.
   * If the user scrolls back up or reaches another emitter element,
   * existing attributes will be removed immediately.
   * Set this option to false to prevent removing of attributes.
   * This can be used to create one-off animations for appearing elements.
   * @type {Boolean}
   */
  rewind: true,

  /**
   * Should smooth scrolling be enabled for all listener elements?
   * Browser support is checked automatically, if set to 'auto'.
   * If you use custom event listeners for your links,
   * you probably want to disable this option (= false).
   * Set this option to true, if you use your own polyfill.
   * The script can only check for native support, not for polyfills.
   * @type {Boolean|'auto'}
   */
  smoothScroll: "auto",

  /**
   * The update method will get called at a limited rate on scroll.
   * By default it will get called 10 times per second.
   * This can limit the FPS in a custom update callback.
   * Feel free to change it to a lower value, if that's the case.
   * @type {Number}
   */
  throttleDelay: 100,

  /**
   * The last emitter element may be "unreachable" on bigger screens.
   * Usually an emitter element is only triggered when the user scrolls past it.
   * However, if the user scrolls to the bottom of the page,
   * the last emitter element will be activated automatically.
   * If linked listener elements should receive their attributes earlier,
   * you should pass a (much) higher value.
   * Negative values (<0) will make the last emitter element unreachable.
   * @type {Number}
   */
  windowBottomOffset: 20
});

You can create as many instances as you like, even with (very) different configurations.

API and Events

Scroll-Reaction.js has a simple API:

// Include scroll-reaction.min.js first!

// Basic Setup
var reaction = new ScrollReaction();

// Access the current scroll position in pixels at any time:
var pixels = reaction.position; // e.g. 750

// Access the current scroll position in percent at any time:
var percentage = reaction.status + "%"; // e.g. 75%

/**
 * Call this function on every update.
 * This includes: scroll, resize and orientation change.
 * In most cases, you don't need to register
 * your own event listeners for these events.
 * Scroll-Reaction.js uses custom event listeners
 * with performance optimizations.
 */
reaction.on("update", function() {
  // Available variables (see above)
  // this.position
  // this.status
});

/**
 * Call this function whenever the user clicks on a link
 * with a Scroll-Reaction.js data attribute (see config).
 * If smoothScroll is explicity set to false,
 * Scroll-Reaction.js won't add event listeners to links.
 * In that case you can register your own event listeners.
 */
reaction.on("click", function() {
  // Available variables (see above)
  // this.position
  // this.status
});

// If you add, reorder or delete emitter or listener elements,
// you should refresh the cache.
reaction.refresh();

// If you add elements or change their height,
// you should update the position and the status.
// Otherwise they will update when the next scroll event occurs.
reaction.update();

// You want the browser to scroll to a specific element?
// Just pass the ID as an argument.
reaction.scrollTo("my-id");

// Scroll to top
reaction.scrollTo();

Help and browser support

Be sure to have a look at the examples to learn more about Scroll-Reaction.js.

If you run into trouble, feel free to post your questions in the issues section.

Scroll-Reaction.js supports all modern browsers (requires ES5). It doesn’t rely on ES6 features, so it should support a fair amount of older browsers as well – even Internet Explorer 9+.

Most modern browsers still don’t support scroll behavior for native smooth scrolling. The default version of Scroll-Reaction.js doesn’t include a polyfill. If you need a polyfill, you can use the file scroll-reaction-with-polyfill.min.js. Thanks to this awesome project!

License

Scroll-Reaction.js is licensed under the MIT license.

Attribution is not required, but always appreciated. Building great things? Show me! :)

Copyright © Tim-Patrick Matthes

1.4.0

5 years ago

1.3.4

5 years ago

1.3.3

5 years ago

1.3.2

5 years ago

1.3.1

6 years ago

1.3.0

6 years ago

1.2.3

6 years ago