What is ScrollOut?

ScrollOut is a JavaScript microlibrary that detects scroll/resize changes in the browser and assigns attributes and live CSS Variables to the scrolling element and a list of targets.

The ScrollOut library does not handle any animation, but it gives you the elements and tools needed to create animations & transitions with JavaScript animation libraries or only CSS!

The general flow is:

  • Decorate your targets with data-scroll attribute
  • Call ScrollOut() from JavaScript
  • Each data-scroll is set to in or out when it comes in or goes out of view
  • As the element scrolls, it flips in and out
  • Enable cssProps in the configuration to add live CSS Variables
  • Animate those elements with CSS or JavaScript!

Getting Started

Installing from a CDN

Include the following script in the head of your document

<script src="https://unpkg.com/scroll-out/dist/scroll-out.min.js"></script>

On document load/ready or in a script at the bottom the of the <body>, do the following:

ScrollOut({
  /* options */
});

Installing from NPM

Install scroll-out from NPM:

npm i scroll-out -S

Then import ScrollOut from the package and call it

import ScrollOut from "scroll-out";

ScrollOut({
  /* options */
});

Compatibility

ScrollOut is compatible with all modern browsers and Internet Explorer. CSS Custom Properties are available to browsers that support CSS Variables (~85% of the current browser market share).

If you experience an issue with a browser that is prior to IE11, please create an issue so we can look at adding support.

Also, there is a well known Edge bug that may prevent transitions from firing properly. This should not be a problem when Edge Chromium is more widely used.

Tips (How do I?...)

Perform a Fade In with CSS

Add this to your css.

[data-scroll] {
  transition: opacity 1s;
}
[data-scroll="in"] {
  opacity: 1;
}
[data-scroll="out"] {
  opacity: 0;
}

Add this to your page to select all elements with data-scroll on them.

<script>
  ScrollOut();
</script>

Perform a Fade with JavaScript

ScrollOut({
  onShown: function(el) {
    // use the web animation API
    el.animate([{ opacity: 0 }, { opacity: 1 }], 1000);
  },
  onHidden: function(el) {
    // hide the element initially
    el.style.opacity = 0;
  }
});

Use it with Animate.css

When using Animate.css, you can trigger animations by adding the animated class.

ScrollOut({
  onShown(el) {
    el.classList.add("animated");
  }
});

Force Animate.css Replay

When using animate.css, you may need to force the animation to play a second time. Luckily there is a handy way to force the browser to reflow the document and replay the animation:

ScrollOut({
  onShown: function(el) {
    // remove the class
    el.classList.remove("animated");

    // force reflow
    void el.offsetWidth;

    // re-add the animated cl
    el.classList.add("animated");
  }
});

This code sample uses the Web Animation API (Available on Chrome and FireFox). The general idea works for any animation library.

Target a Scroll Container

To use a scrolling pane other than the window, provide a scrollingElement as a css selector or an element.

ScrollOut({
  scrollingElement: ".scrollable-pane"
});

Create a Sticky Header

The following example shows how to create a sticky header with ScrollOut.

<html>
  <head>
    <style>
      .hero {
        height: 400px;
      }
      .header {
        position: relative;
        height: 100px;
      }
      .sticky-header {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 100px;
      }
      .sticky-header[data-scroll="in"] {
        position: fixed;
      }
    </style>
  </head>
  <body>
    <div class="hero"></div>
    <div class="header">
      <div class="sticky-header">HEADER</div>
    </div>
    <script>
      ScrollOut({
        targets: ".sticky-header",
        offset: 400
      });
    </script>
  </body>
</html>

Use with Frameworks

Most JS frameworks have setup/teardown methods that should be used when using ScrollOut.

Vue

export default {
  mounted() {
    this.so = ScrollOut({
      scope: this.$el
    });
  },
  destroyed() {
    this.so.teardown();
  }
};

Angular

@Component(/**/)
export class MyComponent implements AfterContentInit, OnDestroy {
  so: any;

  constructor(private el: ElementRef) {}

  ngAfterContentInit() {
    this.so = ScrollOut({
      scope: this.el.nativeElement
    });
  }

  ngOnDestroy() {
    this.so.teardown();
  }
}

I'm having trouble

Don't panic! Here are some common issues that can prevent ScrollOut from working correctly:

  1. Missing <!DOCTYPE html> or the browser is working in quirks mode. One of the biggest symptoms of this is data-scroll="in" and data-scroll="out" being reversed. Ensure the browser is not operating in quirks mode by having the proper DOCTYPE declaration.
  2. The scrollingElement is not provided to ScrollOut and the document.scrollingElement is not the container that is actually scrolling. If your code is setting overflow to something other than the body/html element, it needs to be passed to ScrollOut as scrollingElement.

What's New?

  • v2.2.10 - In this release, offset and threshold have been improved to accept a function instead of just a number. Performance was improved and intermitent first render issues have been fixed.
  • v2.2.2 - Checkout this CodePen post to read about --scroll-percent-x/y, --viewport-x/y, and changes to cssProps
  • v2.0.0 - Checkout this CodePen post for all the exciting new features in 2.0.0

API

Configuration

Options Description
cssProps If true, all CSS Variables will be added to the scrolling element and all targets. If false, only the [data-scroll] property will be modified on targets. For more control, see CSS Props Options
offset The targets become visible when they reach this distance in pixels from the top of the screen. Setting this option overrides all other collision detection. This can also be a function that returns a number.
once Elements will only be changed from scroll-out to scroll-in once. This is useful if you want to transition all elements exactly once. The default value is false.
scope Use this is specify the root element to use when resolving targets. If not specified, the scrollingElement is used.
scrollingElement The scrolling container. When scope is not specified, it is assumed that all targets are children of this element. If not specified, the documentElement is used.
targets An optional list of elements or a css selector. By default, this is [data-scroll]
threshold The ratio of the element that must be visible before it is marked as visible. Providing the value 0.2 would require 20% of the element to be visible before marking it visible. This can also be a function that returns a number.

Special options on Elements

The following attributes can be added to elements to enable options:

  • scrollout-once: add this to enable the once option for a single element

Events

Event Handlers

The following event handlers can be added to the ScrollOut constructor:

ScrollOut({
  onShown: function(element, ctx, scrollingElement) {
    /* Triggered when an element is shown */
  },
  onHidden: function(element, ctx, scrollingElement) {
    /* Triggered when an element is hidden */
  },
  onChange: function(element, ctx, scrollingElement) {
    /* Triggered when an element changes visibility */
  }
});

Event Context (ctx)

The following context object is passed to each of the event handlers.

Property Description
offsetX The distance from the left of the scrolling element
offsetY The distance from the top of the scrolling element
elementWidth The width of the element
elementHeight The height of the element
index The index of the element vs other targets being tracked by ScrollOut.
intersectX The position of an element vs the viewport. Top = -1, In view = 0, 1 = Bottom
intersectY The position of an element vs the viewport. Left = -1, In view = 0, 1 = Right
viewportX The horizontal position of an element relative to the center of viewport. Left = -1, centered = 0, and 1 = Right. This is most useful for parallax.
viewportY The vertical position of an element relative to the center of viewport. Top = -1, centered = 0, and 1 = Bottom. This is most useful for parallax.
visible Equal to 1 if the element is visible in the viewport, 0 if not. Can be tweaked by using the threshold option.
visibleX The ratio of visible horizontal content. 0 if invisible, 1 if 100% visible
visibleY The ratio of visible vertical content. 0 if invisible, 1 if 100% visible

Methods

ScrollOut has a few methods to handle specialized cases. index() and update() can be used for manually refreshing the DOM. teardown is useful when building a Single Page Application.

Method Description
.index() Manually searches for elements. This is intended for when DOM elements are removed or inserted by a JS framework.
.update() Manually checks if the elements have been updated. This is intended for when a JS framework changes the visual layout of the DOM.
.teardown() If you no longer need a ScrollOut instance, call the teardown() function.

Scrolling Element

Scroll Direction

ScrollOut detects the direction on the horizontal and vertical axis. This is useful for creating CSS styles that are different when scrolling down vs scrolling up.

Attributes Description
data-scroll-dir-x The current horizontal direction -1, 1, or 0 of the scroll. -1 is up, and 1 is down.
data-scroll-dir-y The current vertical direction -1, 1, or 0 of the scroll. -1 is left, and 1 is right.
Variable Description
--scroll-dir-x The current horizontal direction -1, 1, or 0 of the scroll. -1 is up, and 1 is down.
--scroll-dir-y The current vertical direction -1, 1, or 0 of the scroll. -1 is left, and 1 is right.

Scroll Percentage

ScrollOut calculates the total percentage of a scrolling element is scrolled and provides that as a CSS Variable. This is useful for parallax backgrounds or other effects.

Variable Description
--scroll-percent-x The ratio of horizontal scroll progress. It starts at 0 and ends at 1.
--scroll-percent-y The ratio of vertical scroll progress. It starts at 0 and ends at 1.

Scroll Targets

Target Dimensions

Variable Description
--element-width The current width of the element
--element-height The current height of the element

Target Position

Variable Description
--intersect-x The position of an element vs the viewport. Left = -1, In view = 0, 1 = Right
--intersect-y The position of an element vs the viewport. Top = -1, In view = 0, 1 = Bottom
--offset-x The number of pixels from the left side of the scrolling element.
--offset-y The number of pixels from the top of the scrolling element
--viewport-x The horizontal position of an element relative to the center of viewport. Left = -1, centered = 0, and 1 = Right. This is most useful for parallax.
--viewport-y The vertical position of an element relative to the center of viewport. Top = -1, centered = 0, and 1 = Bottom. This is most useful for parallax.

Target Visibility

Attribute Description
data-scroll "in" or "out". "in" if the element is visible, "out" if it is not. Decorate your elements with this attribute to automatically target these elements.
Variable Description
--visible The value is 1 if the element is considered visible, 0 if not.
--visible-x The current ratio of visible content on the horizontal axis (0 to 1)
--visible-y The current ratio of visible content on the vertical axis (0 to 1)

CSS Props Options

For performance / cleanliness reasons, it is desirable to opt into particular CSS Variables. In addition to true/false, the cssProps options can also accept an object that describes which properties should be enabled or disabled. When specifying this options object, all variables are opt-in. For instance, in the following examples, only --viewport-y and --visible-y would be set on the elements:

ScrollOut({
  cssProps: {
    viewportY: true,
    visibleY: true
  }
});

Both Target and Scrolling Element CSS Variables are controlled by this option.