Sandbox: JavaScript

The MooTools Bootstrap implementation comes with Behavior.Affix that allows you to pin an object in place when the page is scrolled to a certain point. The typical example here is like the menu on the left here in sandbox where a nav item is pegged in place, but when you reach the top of the page it's allowed to move with the scroll offset. You can see an example on the Clientcide MooTools Bootstrap example.

All that Behavior.Affix really does though is add a class to the element when the window is scrolled to a certain offset. Because of this, we can also use this to change the overflow values on an element. Because the example here requires you to scroll the page, this example does not use the typical example found in other Sandbox demos, so we'll show you what the code looks like down below.

Generic Demo

Scroll this page down and you'll see how the content below changes to overflow:auto when you scroll the page down 100px.

Note Scroll down past the hipster ipsum to see more docs.

Here, have some Hipster Ipsum. Tofu gastropub photo booth art party Godard beard, flexitarian asymmetrical brunch Wes Anderson. Asymmetrical craft beer XOXO cornhole farm-to-table, ethnic cardigan mustache paleo. Fashion axe street art cray Odd Future, Shoreditch 8-bit keffiyeh locavore cornhole 90's. Four loko hashtag master cleanse kitsch beard shabby chic. Portland Schlitz chambray, freegan hella street art Vice disrupt asymmetrical Marfa. Bicycle rights typewriter sartorial whatever Blue Bottle four loko. Kogi flexitarian 3 wolf moon, jean shorts banjo forage kale chips.

8-bit squid meggings Etsy flannel, cliche shabby chic polaroid Bushwick fixie pickled selfies pug Williamsburg. Plaid flexitarian brunch Odd Future scenester whatever, Banksy selfies Intelligentsia tote bag Pinterest. Salvia VHS locavore ethical wolf selfies. Fap disrupt mustache Williamsburg typewriter. McSweeney's Helvetica chia, slow-carb gastropub umami mixtape literally. YOLO sartorial banh mi ethnic artisan. Food truck cray leggings retro, High Life single-origin coffee jean shorts cornhole literally mlkshk paleo brunch tofu pork belly before they sold out.

Retro keytar post-ironic, Pitchfork shabby chic +1 ethical bicycle rights kale chips typewriter sartorial. Godard church-key pop-up, Truffaut Brooklyn shabby chic readymade gluten-free umami tattooed flexitarian Intelligentsia hella synth. McSweeney's ugh paleo Truffaut semiotics bitters, pork belly gentrify PBR art party. Direct trade keytar brunch Thundercats. Bespoke polaroid Helvetica, asymmetrical Portland shabby chic iPhone ugh semiotics chambray ennui gastropub. Hashtag gluten-free bicycle rights, +1 wayfarers wolf hoodie selvage slow-carb salvia PBR. Pour-over Odd Future retro Pitchfork Tonx.

Blog aesthetic art party Odd Future. Letterpress cred High Life banh mi photo booth actually. Pug bicycle rights craft beer wayfarers, you probably haven't heard of them kitsch sriracha paleo. Locavore chillwave ugh, master cleanse banh mi American Apparel XOXO vegan Pitchfork jean shorts meggings. 8-bit VHS next level, fashion axe squid tattooed Neutra. Mustache Brooklyn fixie Banksy master cleanse. Scenester Shoreditch ugh, American Apparel wolf cornhole meh Marfa lo-fi Neutra farm-to-table single-origin coffee.

8-bit squid meggings Etsy flannel, cliche shabby chic polaroid Bushwick fixie pickled selfies pug Williamsburg. Plaid flexitarian brunch Odd Future scenester whatever, Banksy selfies Intelligentsia tote bag Pinterest. Salvia VHS locavore ethical wolf selfies. Fap disrupt mustache Williamsburg typewriter. McSweeney's Helvetica chia, slow-carb gastropub umami mixtape literally. YOLO sartorial banh mi ethnic artisan. Food truck cray leggings retro, High Life single-origin coffee jean shorts cornhole literally mlkshk paleo brunch tofu pork belly before they sold out.

Retro keytar post-ironic, Pitchfork shabby chic +1 ethical bicycle rights kale chips typewriter sartorial. Godard church-key pop-up, Truffaut Brooklyn shabby chic readymade gluten-free umami tattooed flexitarian Intelligentsia hella synth. McSweeney's ugh paleo Truffaut semiotics bitters, pork belly gentrify PBR art party. Direct trade keytar brunch Thundercats. Bespoke polaroid Helvetica, asymmetrical Portland shabby chic iPhone ugh semiotics chambray ennui gastropub. Hashtag gluten-free bicycle rights, +1 wayfarers wolf hoodie selvage slow-carb salvia PBR. Pour-over Odd Future retro Pitchfork Tonx.

Code

The example above looks like this:

  <style>
    .underscroll {
      height: 400px;
      overflow: hidden;
      padding: 0px 8px;
    }
    .underscroll-center {
      overflow: auto;
      box-shadow: inset 1px 4px 9px -6px;
    }
  

  <div class="underscroll" data-behavior="BS.Affix" data-bs-affix-options="
    'top': 300,
    'classNames': {
      'top': 'underscroll-top',
      'bottom': 'underscroll-bottom',
      'affixed': 'underscroll-center'
    }
  ">
    ... some content ...
  </div>

Header w/ Shadow Demo

Optional Less Component

Include thanx-components/underscrolls.less in your build to get the `underscroll-shadow-center` class that automatically adds a shadow for you.

This example specifies that when you scroll the list below a few pixels (5px) the header gets a shadow.

This header gets a shadow when list scrolls

  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
<h3 style="padding: 8px; margin: 0;" class="grey-20-bkg" data-behavior="BS.Affix" data-bs-affix-options="
    'top': 5,
    'classNames': {
      'affixed': 'underscroll-shadow-center'
    },
    'monitor': '!div ul'
  ">This header gets a shadow when list scrolls</h3>
<ul class="overflow-y" style="height: 100px; border: 1px solid #ccc;">
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
</ul>

What's Going On

The BS.Affix behavior simply adds a class to your element based on the window's scroll offset. You can define the offsets with the top and bottom options and you can define the classes given to your element when the window is in those regions. The defaults use Bootstrap standard affix classes to fix their positions.

The default classes still require specific configuration to get the appropriate behavior (as the classes don't know what position your element should be fixed at when they are applied), but using it for underscroll requires more work. The tricky part is when you want your element to eat up all available space. If your element doesn't contain enough space to scroll down far enough then the center styles will never get applied. So to get a 100% height UI to work you have to have a style that says that your content is overflow: visible and then switches to overflow: auto.

This example - with the text in the middle of the page - isn't a great example. It's more typical to have a full screen experience where the header scrolls up and then freezes while the content below becomes scrollable. There are a couple of ways to accomplish this including changing the header's styles to become a fixed-position element. Your use case will dictate how best to accomplish it.

Specifying an Element Instead Of A Numerical Offset

You can, optionally, specify an element instead of a numerical offset for the top and bottom of the area. This allows you to have the user scroll to an element and then see a change.

This header turns green

  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • When I'm visible, the header turns green!
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
<h3 style="padding: 8px; margin: 0;" data-behavior="BS.Affix" data-bs-affix-options="
    'classNames': {
      'top': 'grey-20-bkg',
      'bottom': 'grey-20-bkg',
      'affixed': 'emerland-light-bkg'
    },
    'affixAtElement': {
      'top': {
        'element': '!div ul li.target'
      }
    },
    'monitor': '!div ul'
  ">This header turns green</h3>
<ul class="overflow-y" style="height: 100px; border: 1px solid #ccc;">
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li class="target">When I'm visible, the header turns green!</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
</ul>

Persistence

The persist option forces the class to become inactive whenever the affixed state is reached. This basically means that whenever the user scrolls to the specified offset the affixed class is added and the class stops monitoring scrolls.

This header turns green... and stays green

  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • When I'm visible, the header turns green! It stays green, even when you scroll me back out of view.
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
  • stuff
<h3 style="padding: 8px; margin: 0;" data-behavior="BS.Affix" data-bs-affix-options="
    'classNames': {
      'top': 'grey-20-bkg',
      'bottom': 'grey-20-bkg',
      'affixed': 'emerland-light-bkg'
    },
    'affixAtElement': {
      'top': {
        'element': '!div ul li.target'
      }
    },
    'monitor': '!div ul',
    'persist': true
  ">This header turns green... and stays green</h3>
<ul class="overflow-y" style="height: 100px; border: 1px solid #ccc;">
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li class="target">
    When I'm visible, the header turns green! It <strong>stays</strong> green, even when you scroll
    me back out of view.
  </li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
  <li>stuff</li>
</ul>

Related Documentation

Note: Not all links in these work.

Behavior Filter: Behavior.BS.Affix

A behavior filter to instantiate Bootstrap Affix functionality.

Demo / Fancy Docs

http://anutron.github.com/mootools-bootstrap/#affix

Example

<a data-behavior="BS.Affix"
    data-bs-affix-options="
        'top': 10
    ">I stick around!</a>

Options

  • top - (number) The distance from the top that the user must scroll before the affix class is added and the affix-top class is removed. Defaults to 0.
  • bottom - (number) The distance from the top that the user must scroll before the affix class is removed and the affix-bottom class is added. Specify a negative number to have it measure from the bottom of the window height.
  • classNames - (object) The class names to apply in the various states. Defaults to top: "affix-top", bottom: "affix-bottom", affixed: "affix". These should be defined in your CSS as you like. You can also manually affix location for the element using the events listed below.
  • monitor - (element) The element that is monitored for scrolls; defaults to the window.
  • persist - (boolean) If true, the class never leaves the affixed state.
  • affixAtElement - (object) If specified, allows you to define an element that the user scrolls to instead of a fixed offset. See docs for Bootstrap.Affix and notes below.

Using affixAtElement

The affixAtElement option allows you to specify an element or elements that define the boundary for the center class (the affixed class). You can specify a different element for the "top" and for the "bottom". If you define only a value for the top then the class uses that element for the bottom as well. Using this functionality you can, for example, have an element that represents the top of the affixed area and another for the bottom or you can use the same element, effectively saying "when this element is visible add this class to my element".

Because the Affix class is not limited to only the affixed behavior (you can add any class you like), you could have some element change color when the user scrolls another into view.

Note that unlike the options signature in Bootstrap.Affix, the element options here are selectors relative to the element with the behavior filter upon it.

Example:

<div data-behavior="BS.Affix"
    data-bs-affix-options="
        'affixAtElement': {
            'top': {
                'element': 'span.foo'
            }
        }
    ">...</div>

This example configures the behavior to add the affixed class (the default) to our div whenever the element span.foo is scrolled into view. When that element is scrolled past, the affix-bottom class (the default) is substituted.

Defaults

The default values for the affixAtElement option are as follows:

affixAtElement: {
    top: {
        element: null,
        edge: 'top',
        offset: 0
    },
    bottom: {
        element: null,
        edge: 'bottom',
        offset: 0
    }
}

If you specify a top and/or a bottom the class will measure their positions on startup and use that for the top/bottom boundaries for the center affix class.

Note

The refresh method (that re-calculates the locations of these elements) is called whenever any other filter fires the ammendDom, destroyDom, or display:layout events.

Class: Bootstrap.Affix

Implements the basic functionality of Bootstrap Affix which adds a class to an element when it is above, in, and below a given scroll range.

Implements

Bootstrap.Affix Method: constructor

Syntax

new Bootstrap.Affix(element[, options]);

Arguments

  1. element - (mixed) A string of the id for an Element or an Element that should be changed when the window scrolls.
  2. options - (object, optional) a key/value object of options

Options

  • top - (number) The distance from the top that the user must scroll before the affix class is added and the affix-top class is removed. Defaults to 0.
  • bottom - (number) The distance from the top that the user must scroll before the affix class is removed and the affix-bottom class is added. Specify a negative number to have it measure from the bottom of the window height.
  • classNames - (object) The class names to apply in the various states. Defaults to top: "affix-top", bottom: "affix-bottom", affixed: "affix". These should be defined in your CSS as you like. You can also manually affix location for the element using the events listed below.
  • monitor - (element) The element that is monitored for scrolls; defaults to the window.
  • persist - (boolean) If true, the class never leaves the affixed state.
  • affixAtElement - (object) If specified, allows you to define an element that the user scrolls to instead of a fixed offset. See below.

Events

  • pin - (function) Fired when the element is below the top and above the bottom (i.e. it is within the scroll boundaries).
  • unPin - (function) Fired when the element is out of scroll range. If it is below the bottom of the range, this event is passed a boolean true.

Using affixAtElement

The affixAtElement option allows you to specify an element or elements that define the boundary for the center class (the affixed class). You can specify a different element for the "top" and for the "bottom". If you define only a value for the top then the class uses that element for the bottom as well. Using this functionality you can, for example, have an element that represents the top of the affixed area and another for the bottom or you can use the same element, effectively saying "when this element is visible add this class to my element".

Because the Affix class is not limited to only the affixed behavior (you can add any class you like), you could have some element change color when the user scrolls another into view.

Example:

var myAffix = new Bootstrap.affix(element, {
    affixAtElement: {
        top: {
            element: document.id('someTarget')
        }
    }
});

Defaults

The default values for the affixAtElement option are as follows:

affixAtElement: {
    top: {
        element: null,
        edge: 'top',
        offset: 0
    },
    bottom: {
        element: null,
        edge: 'bottom',
        offset: 0
    }
}

If you specify a top and/or a bottom the class will measure their positions on startup and use that for the top/bottom boundaries for the center affix class.

Bootstrap.Affix Method: refresh

Re-measures the locations of the top/bottom elements in the affixAtElement option (if defined);

Syntax

myAffix.refresh();

Returns

  • (object) This Bootstrap.Affix instance.

Note

Bootstrap.Affix automatically calls refresh whenever the window is resized.

Bootstrap.Affix Method: attach

Attach scroll listeners (enable the instance).

Syntax

myAffix.attach();

Returns

  • (object) This Bootstrap.Affix instance.

Bootstrap.Affix Method: detach

Detaches the scroll listeners (disables the instance).

Syntax

myAffix.detach();

Returns

  • (object) This Bootstrap.Affix instance.

Bootstrap.Affix Method: pin

Fires the pin event and adds the pinned-state class.

Syntax

myAffix.pin();

Returns

  • (object) This Bootstrap.Affix instance.

Bootstrap.Affix Method: unpin

Fires the unPin event and adds the unpinned-state class.

Syntax

myAffix.unpin([isBottom]);

Arguments

  1. isBottom - (boolean) if true adds the bottom-state class. Otherwise the top.

Returns

  • (object) This Bootstrap.Affix instance.