Basics:
Options
Supported Elements
Flexbox
Initialization:
Default
jQuery
Instance Methods:
options
update
sleep
scroll
scrollStop
getElements
getState
destroy
ext
addExt
removeExt
Global Methods:
defaultOptions
globals
extension
valid
Extensions:
Basics
Create Extensions
Themes & Styling:
Built-in Themes
Class Names
Styling
Structure:
DOM Elements
Options
Summarized default options

    {
        className            : "os-theme-dark",
        resize               : "none",
        sizeAutoCapable      : true,
        clipAlways           : true,
        normalizeRTL         : true,
        paddingAbsolute      : false,
        autoUpdate           : null,
        autoUpdateInterval   : 33,
        updateOnLoad         : ["img"],
        nativeScrollbarsOverlaid : {
            showNativeScrollbars   : false,
            initialize             : true
        },
        overflowBehavior : {
            x : "scroll",
            y : "scroll"
        },
        scrollbars : {
            visibility       : "auto",
            autoHide         : "never",
            autoHideDelay    : 800,
            dragScrolling    : true,
            clickScrolling   : false,
            touchSupport     : true,
            snapHandle       : false
        },
        textarea : {
            dynWidth       : false,
            dynHeight      : false,
            inheritedAttrs : ["style", "class"]
        },
        callbacks : {
            onInitialized               : null,
            onInitializationWithdrawn   : null,
            onDestroyed                 : null,
            onScrollStart               : null,
            onScroll                    : null,
            onScrollStop                : null,
            onOverflowChanged           : null,
            onOverflowAmountChanged     : null,
            onDirectionChanged          : null,
            onContentSizeChanged        : null,
            onHostSizeChanged           : null,
            onUpdated                   : null
        }
    }

Documentation
Click on an option to toggle its description and additional info.

Option Name | Type(s) | Valid values | Default Value
className | string / null | - | "os-theme-dark"
The class name which shall be added to the host element. You can add multiple class names if you separate them by spaces. This option is intended for styling / theming purposes. If this option is null, then the class `.os-theme-none` gets added automatically to the host element. This class ensures that the scrollbars won't have any appearance.
resize | string | `[ "none", "both", "horizontal", "vertical" ]` shorthand: `[ "n", "b", "h", "v" ]` | "none"

The resize behavior of the host element. This option works exactly like the CSS3 resize property.
This option is ignored if the target-element is the body element. The window itself can be resized and thus this option isn't needed.
"none"
The host element is not resizable.
"both"
The host element is resizable in the horizontal and vertical direction.
"horizontal"
The host element is resizable in the horizontal direction.
"vertical"
The host element is resizable in the vertical direction.

sizeAutoCapable | boolean | - | true

Indicates whether the host element is capable of "auto" sizes such as: `width: auto` and `height: auto`. If set to false and the property width or height is "auto", the rendered width or height of the content will be zero.
If you are applying OverlayScrollbars to a flexbox-element set this option to false to ensure correct functionality.
This option is ignored if the target-element is the body element, because in this case the size must be 100% (on both axis) to simulate the viewport correctly.

clipAlways | boolean | - | true
Indicates whether the content shall be clipped always. If false the content gets only clipped if an overflow on the bottom or right edge exists. - Use the capabilities demo, set the host-element height dropdown value to "Auto" and play with the "Clip Always" checkbox to understand this option.
normalizeRTL | boolean | - | true
Indicates whether RTL scrolling shall be normalized. Every browser handles RTL scrolling differently. With this option set to true, every call to the scroll method will be normalized to guarantee the same functionality on every browser.
paddingAbsolute | boolean | - | false
Indicates whether the padding for the content shall be absolute. Absolute padding means that the content will always have the defined spacing to the edge, regardless of the scroll-offset. Every browser handles normal padding on scrolled content differently. This options gives you also the possibility to handle padding the same way in every browser.
autoUpdate | boolean / null | - | null

Indicates whether the plugin instance shall be updated continuously within a update loop.
true
The instance is using the update loop.
On every iteration of the loop the DOM / instance is checked for changes. Only if there are any changes the DOM / instance will be updated. If the browser supports modern change detection mechanisms, they get turned off.
false
The instance isn't using the update loop.
If the browser supports modern change detection mechanisms, they gets turned on and the instance is using them.
null
The plugin chooses. - It checks if the browser supports modern change detection mechanisms. If yes, then the plugin will use these for updating (alike false), else it will fallback to the update loop (alike true). This option is highly recommended to guarantee best performance and browser compatibility.
-
Note: To ensure maximum efficiency there is only ONE update loop across ALL instances. The loop is only running if at least one instance is using it. The loop interval is the value of the smallest "autoUpdateInterval" option across all instances which are using the loop.

autoUpdateInterval | number | - | 33
The interval in milliseconds in which an auto update shall be performed for this instance.
updateOnLoad | string / array / null | - | ["img"]
`added in v1.12.0` Selectors of which the elements load event shall be handled by the plugin. Thats means OverlayScrollbars will trigger a automatic update if a element with a matching selector emits a `load` event. Per default OverlayScrollbars will update automatically if a `img` element loads.

nativeScrollbarsOverlaid : {

These options are only respected if the native scrollbars are overlaid.

Option Name | Type(s) | Valid values | Default Value
showNativeScrollbars | boolean | - | false
Indicates whether the native overlaid scrollbars shall be visible. true Shows the native scrollbars and hides the custom scrollbars, but still initializes the plugin and dispatches all callbacks. false Hides the native scrollbars and acts like if they were non-overlay-scrollbars.
initialize | boolean | - | true

Indicates whether the plugin shall be initialized even if the native scrollbars are overlaid.

true

Initializes the plugin normally.

false

Stops the plugin from initializing and fires the `'onInitializationWithdrawn'` callback.
-
Use false if you want prevent the plugin to initialize for example on mobile browsers.
If you initialize the plugin on the body element, I highly recommend to set this option to false.

}

overflowBehavior : {

Defines how the overflow should be handled for each axis, e.g. if scrolling shall be possible or not.

Option Name | Type(s) | Valid values | Default Value
x | string | `[ "hidden", "scroll", "visible-hidden", "visible-scroll" ]` shorthand: `[ "h", "s", "v-h", "v-s" ]` | "scroll"

The overflow behavior for the x (horizontal) axis.
"hidden"
If the x-axis has an overflow, the viewport becomes `overflow-x: hidden`.
In short: Horizontal scrolling is NOT possible and the content is clipped.
"scroll"
If the x-axis has an overflow, the viewport becomes `overflow-x: scroll`.
In short: Horizontal scrolling is possible and the content is clipped.
"visible-hidden"
If the x-axis has an overflow, the viewport becomes `overflow-x: visible`. If the y-axis has an overflow and the overflow behavior of the y-axis is "hidden" or "scroll", the viewport becomes `overflow-x: hidden`.
In short: The content is not clipped, but if the y-axis has an overflow the content is clipped and horizontal scrolling is NOT possible.
"visible-scroll"
If the x-axis has an overflow, the viewport becomes `overflow-x: visible`. If the y-axis has an overflow and the overflow behavior of the y-axis is "hidden" or "scroll", the viewport becomes `overflow-x: scroll`.
In short: The content is not clipped, but if the y-axis has an overflow the content is clipped and horizontal scrolling is possible.

y | string | `[ "hidden", "scroll", "visible-hidden", "visible-scroll" ]` shorthand: `[ "h", "s", "v-h", "v-s" ]` | "scroll"

The overflow behavior for the y (vertical) axis.
"hidden"
If the y-axis has an overflow, the viewport becomes `overflow-y: hidden`.
In short: Vertical scrolling is NOT possible and the content is clipped.
"scroll"
If the y-axis has an overflow, the viewport becomes `overflow-y: scroll`.
In short: Vertical scrolling is possible and the content is clipped.
"visible-hidden"
If the y-axis has an overflow, the viewport becomes `overflow-y: visible`. If the x-axis has an overflow and the overflow behavior of the x-axis is "hidden" or "scroll", the viewport becomes `overflow-y: hidden`.
In short: The content is not clipped, but if the x-axis has a overflow the content is clipped and vertical scrolling is NOT possible.
"visible-scroll"
If the y-axis has an overflow, the viewport becomes `overflow-y: visible`. If the x-axis has an overflow and the overflow behavior of the x-axis is "hidden" or "scroll", the viewport becomes `overflow-y: scroll`.
In short: The content is not clipped, but if the x-axis has an overflow the content is clipped and vertical scrolling is possible.

}

scrollbars : {

Defines the behavior of the custom scrollbars.

Option Name | Type(s) | Valid values | Default Value
visibility | string | `[ "visible", "hidden", "auto" ]` shorthand: `[ "v", "h", "a" ]` | "auto"
The basic visibility of the scrollbars. "visible" The scrollbars are always visible, regardless of whether the appropriate axis has an overflow. "hidden" The scrollbars are never visible, regardless of whether the appropriate axis has an overflow. "auto" The scrollbars are only visible if the appropriate axis has an overflow.
autoHide | string | `[ "never", "scroll", "leave", "move" ]` shorthand: `[ "n", "s", "l", "m" ]` | "never"

The possibility to hide visible scrollbars automatically after a certain action.
"never"
The scrollbars never get hidden automatically.
"scroll"
The scrollbars get hidden automatically after a scroll.
"leave"
The scrollbars get hidden automatically after the mouse has left the host-element.
"move"
The scrollbars get hidden automatically after a scroll and after the mouse has stopped moving. `added in v1.4.0`

autoHideDelay | number | - | 800
The delay in milliseconds before the scrollbars get hidden automatically.
dragScrolling | boolean | - | true
Defines whether the scrollbar-handle supports drag scrolling. If set to true, it's possible to drag the scrollbar-handle to change the scroll-offset.
clickScrolling | boolean | - | false
Defines whether the scrollbar-track supports click scrolling. If set to true, it's possible to click on the scrollbar-track to change the scroll-offset.
touchSupport | boolean | - | true
Indicates whether the scrollbar reacts to touch events.
snapHandle | boolean | - | false
`added in v1.7.0` Indicates whether the scrollbar handle-offset shall be snapped or not. This option is only interesting if you use CSS Scroll snapping. Some browsers, like Google Chrome, will snap the scrollbar handle to the next possible position. By default the unsnapped (normal) handleOffset will be used, but you can change this behavior with this option.

}

textarea : {

Defines special behavior of textarea elements.

Option Name | Type(s) | Valid values | Default Value
dynWidth | boolean | - | false
Indiactes whether the textarea width will be dynamic (content dependent). This effect will only take place if the `sizeAutoCapable` option is true and the textarea has the HTML attribute `wrap="off"` applied. Also the host-elements CSS must be `width: auto` in combination with `float: left` or `float: right`.
dynHeight | boolean | - | false
Indiactes whether the textarea height will be dynamic (content dependent). This effect will only take place if the `sizeAutoCapable` option is true and the host-element has the CSS rule `height: auto` applied.
inheritedAttrs | string / array / null | - | ["style", "class"]

`added in v1.6.0`
You can pass a array of strings which represents attribute names: `["style", "class"]`
or a string where you separate multiple attributes with a whitespace: `"style class"`
or `null` which represents a empty array, a empty string or simply no attributes.
During initialization: Attributes which the generated host-element shall inherit from from the target textarea-element.
During destruction: Attributes which the target textarea-element shall inherit from from the generated host-element.
This option was created to increase the control over the styling of textarea instances, but you can use it for any kind of attributes.
Let's say you initialize the plugin to: `<textarea class="foo bar" style="background: red;"></textarea>` and the inheritedAttrs are `["style", "class"]`. Then the resulting generated DOM structure will look like this:

    <!-- the host-element -->
    <div class="foo bar os-host-textarea ..." style="background: red;">
        <!-- ... -->
        <textarea class="foo bar" style="background: red;"></textarea>
        <!-- ... -->
    </div>

If the inheritedAttrs would be `null` then the host-element wouldn't have the style and the class attributes of the textarea element. This was the default behavior before this option was introduced.

}

callbacks : {

Callbacks for specific events.

The "this" context of every callback is the current instance of the plugin.

Option Name | Type(s) | Valid values | Default Value
onInitialized | function / null | - | null
Gets fired after the plugin was initialized. It takes no arguments. `onInitialized : function() { }`
onInitializationWithdrawn | function / null | - | null
Gets fired after the initialization of the plugin was aborted due to the option: `nativeScrollbarsOverlaid : { initialize : false }`. It takes no arguments. `onInitializationWithdrawn : function() { }`
onDestroyed | function / null | - | null
Gets fired after the plugin was destryoed. It takes no arguments. `onDestroyed : function() { }`
onScrollStart | function / null | - | null
Gets fired after the user starts scrolling. It takes one argument. `onScrollStart : function(eventArgs) { }` The passed argument is the scroll argument which gets also passed to the "native" scroll callback. Read more about it
onScroll | function / null | - | null
Gets fired after every scroll. It takes one argument. `onScroll : function(eventArgs) { }` The passed argument is the scroll argument which gets also passed to the "native" scroll callback. Read more about it
onScrollStop | function / null | - | null
Gets fired after the user stops scrolling. It takes one argument. `onScrollStop : function(eventArgs) { }` The passed argument is the scroll argument which gets also passed to the "native" scroll callback. Read more about it
onOverflowChanged | function / null | - | null

Gets fired after the overflow has changed.
Example: the content gets smaller and thus the overflow disappears. It takes one argument.
`onOverflowChanged : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        x             : boolean,
        y             : boolean,
        xScrollable   : boolean,
        yScrollable   : boolean,
        clipped       : boolean
    }

Description:
x
Indicates whether the x-axis has an overflow. This overflow must not be scrollable.
y
Indicates whether the y-axis has an overflow. This overflow must not be scrollable.
xScrollable
Indicates whether the x-axis is scrollable.
(To be scrollable the axis needs to have an overflow and a "scroll" / "visible-scroll" overflow behavior.)
yScrollable
Indicates whether the y-axis is scrollable.
(To be scrollable the axis needs to have an overflow and a "scroll" / "visible-scroll" overflow behavior.)
clipped
Indicates whether the content is clipped due to an overflow.
(Thus it can be false even if `contentClipAlways : true` is set.

onOverflowAmountChanged | function / null | - | null

Gets fired after the overflow amount has changed.
Example: the content gets a bit larger and thus the overflow amount is now higher. It takes one argument.
`onOverflowAmountChanged : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        x : number,
        y : number
    }

Description:
x
The overflow amount on the x-axis in pixels.
y
The overflow amount on the y-axis in pixels.

onDirectionChanged | function / null | - | null

Gets fired after the direction has changed. It takes one argument.
`onDirectionChanged : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        isRTL : boolean,
        dir   : string
    }

Description:
isRTL
Indicates if the new direction is RTL.
dir
The new direction as string. ("ltr" or "rtl")

onContentSizeChanged | function / null | - | null

Gets fired after the content size has changed. It takes one argument.
`onContentSizeChanged : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        width  : number,
        height : number
    }

Description:
width
The content width in pixels.
height
The content height in pixels.

onHostSizeChanged | function / null | - | null

Gets fired after the host size or host padding has changed. It takes one argument.
`onHostSizeChanged : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        width  : number,
        height : number
    }

Description:
width
The host-element width in pixels.
height
The host-element height in pixels.

onUpdated | function / null | - | null

Gets fired after the host size has changed. It takes one argument.
`onUpdated : function(eventArgs) { }`
eventArgs documentaton:
Structure:

    eventArgs : {
        forced  : boolean
    }

Description:
forced
Indicates whether the update was forced due to the "force" parameter in the update method.

}

Supported Elements
General
Basically the plugin can be initialized to any DOM element which can contain DOM elements and supports scrolling.
However, `display : inline` elements does not support scrolling at all. If you initialize the plugin to a inline element, the plugin will not work crrectly, and the element dimensions will be wrong aswell. After you changed the display property to something else, it will work correctly again.
The plugin was tested with the following display values: `display : block;
display : inline-block;` Since you can wrap any element which has one of those values, they should suit for every application.
Body element
The body element is not really special, because it supports all criteria, but there is a case which is different on this element.
Without the plugin initialized the scroll viewport of your whole content is the window. But after the initialization of the plugin, the body element itself becomes new scroll viewport of your whole content.
That means, if you want to specify a `min-height` or `min-width` for your content, you have to do it with this two selectors:

    body.os-host > .os-padding > .os-viewport > .os-content,
    body.os-host > .os-padding > .os-viewport > .os-content-arrange {
        min-width  : 800px;
        min-height : 600px;
    }

Please use always both selectors and not just one.
You could also specify a `min-height` or `min-width` directly for the body element, but that wouldn't make any sense, since you want the body element to be always as big as the window, to simulate a correct viewport. Besides that, the plugin style overrides your body min size(s) to 0 if the plugin is applied to the body element.
Textarea elements
Textarea elements are special. Although they can't contain any DOM elements, the plugin has extended support for them.
Your textarea element will be wrapped inside a generated element, please read the DOM Elements section for more information.
Because of this wrapping you might have to redefine the styles of your textarea element.
The plugin offers the basic selector `.os-host-textarea`, every textarea-host-element has this class applied.
For individual styling use the `inheritedAttrs` or `className` options, to give your textarea individual classes or styles.
After the plugin is applied to your textarea, the textarea is capable of dynamic height and dynamic width.
Dynamic height can be achieved if the option `textarea.dynHeight` is set to true, then the host-element must have the css property `height: auto` set.
Dynamic width can be achieved if the option `textarea.dynWidth` is set to true, then the host-element must have the css properties `width: auto` & `float: left` set, additionally your textarea element must have the html attribute `wrap="auto"` applied, to disable the autowrapping.
Use the textarea demo to test dynamic sized textareas.
Unsupported elements
Unsupported are the following elements:
`img, video, audio, input, embed, object, canvas, button, datalist, fieldset, label, legend, meter, optgroup, option, output, progress, select, [... and maybe more]`
If you need support for a yet unsupported element, please open a issue on github.
Flexbox
General
The plugin was built to be used on "normal" elements, however flexbox is a popular and accepted standard.
Currently I haven't managed to create a automatic and reliable flexbox detection, so you have to take action by yourself:
OverlayScrollbars `v1.5.0 or higher`
Append the class `os-host-flexbox` to your target element.
OverlayScrollbars `lower than v1.5.0`
Try to initialize the plugin with the option `sizeAutoCapable : false` and set the overflow style of the target element to `overflow: hidden`.
In the most cases this should be enough.
However if the plugin isn't updating correctly or if the plugin isn't working at all, I can only recommend to use / create a inner-div with the style `display: block; height: 100%; width: 100%;` and initialize to plugin to that inner-div. With this setup the plugin will definitely work.
If you need help with a special flexbox case, please open a issue on github with a small demo.
I'll do my best to solve your problem.
Default initialization
Single element
The initialization of the plugin for a cerain element is very easy:
In order to initialize the plugin, you have to pass at least a empty object as second argument.

    //initializes the plugin to a single element and returns its instance
    var instance = OverlayScrollbars(document.getElementById(id), { /* your options */ });

The first argument is the element or the elements to which the plugin shall be initialized. The second argument represents the options with which the plugin shall be initialized.
If you initialize the plugin to a single element, this method will return the instance of the plugin.
You can get the current instance with the same method.
If you don't pass a object as second argument, the method returns the instance.

    //returns the plugin instance or undefined if the element has no instance
    var instance = OverlayScrollbars(document.getElementById(id));

If you have initialized the plugin and try to initialize it again, it will be handled as if you call the options method:

     //initializes plugin
    OverlayScrollbars(document.getElementById(id), { });

    //... later
    //is the same as .options({ resize : "both" }) because the plugin is initialized already
    OverlayScrollbars(document.getElementById(id), { resize : "both" });

Multiple elements
The initialization for multiple elements works like the initialization for a single element. The only difference is, that the initialization method will return a array of instances.

    //initialize plugin with custom options on all div elements and return all instances as array
    var instances = OverlayScrollbars(document.querySelectorAll("div"), { });

If you need the instances of multiple element you can do it the same way as for a single element:

    //get the instance information of all elements on your page and store it into a variable
    //the array can contain undefined entries
    var instances = OverlayScrollbars(document.querySelectorAll("*"));

    for(var i = 0; i < instances.length; i++) {
        //check for validity
        if(instances[i] !== undefined) {
            //do domething with the instance
        }
    }

I've built-in a filtering possibility, if you want an array only with not undefined instances:
This will only work if the first argument returns multiple HTML elements.

    //returns an array with all instances which are not undefined
    var instances = OverlayScrollbars(document.querySelectorAll("*"), "!");

    for(var i = 0; i < instances.length; i++) {
        //do something with the instance
    }

Since `v1.6.0` you can pass a custom filtering function.
This function has to return a boolean and takes two arguments:
The first argument is called element. This is the current HTMLElement which gets checked.
The second argument is called instance. This is the OverlayScrollbars instance of the current element which gets checked.

    //returns an array with all instances which are not undefined and applied to a div-tag-element
    var instances = OverlayScrollbars(document.querySelectorAll("*"),
        function(element, instance) {
            return element.tagName === 'DIV' && instance !== undefined;
        }
    );

    for(var i = 0; i < instances.length; i++) {
        //do something with the instance
    }

Initialize with Extensions `added in v1.5.0`
The initialization with extensions provides a possibility to initialize your instance with one or multiple extensions.
You simply have to pass a third argument which has to be a string, an array of strings or an object. This argument represents the extensions which shall be added right after the initialization is complete.
Let's make some examples:

    //register a extension with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });
    //register a 2nd extension with the name "myOtherExtension"
    OverlayScrollbars.extension("myOtherExtension", function() { return { }; });

    //initialize the plugin with just one extension via string
    OverlayScrollbars((document.getElementById(id), { }, "myExtension");

    //initialize the plugin with multiple extensions via array of strings
    OverlayScrollbars((document.getElementById(id), { }, [ "myExtension", "myOtherExtension" ]);

    //initialize the plugin with extensions with custom options via object
    OverlayScrollbars((document.getElementById(id), { }, {
        "myExtension"      : { /* options for "myExtension" */ },
        "myOtherExtension" : { /* options for "myOtherExtension" */ },
    });

jQuery initialization
Single element
The initialization of the plugin for a certain element is very easy and it won't break the jQuery chain:
You have to pass at least an empty object in order to initialize the plugin.

    //initializes the plugin with empty options
    $(id).overlayScrollbars({ /* your options */ });

The object which is passed to this method represents the options with which the plugin shall be initialized.
You can get the current instance with the same method.
If you don't pass an object the method returns the instance.

    //returns the plugin instance or undefined if the element has no instance
    var instance = $(id).overlayScrollbars();

Due to the fact that the initialization won't break the jQuery chain you can initialize and store the instance in just one line:

     //initializes plugin and stores the instance into a variable
    var instance = $(id).overlayScrollbars({ }).overlayScrollbars();

If you have initialized the plugin and try to initialize it again, it will be handled as if you called the options method:

     //initializes plugin
    $(id).overlayScrollbars({ });

    //... later
    //is the same as .options({ resize : "both" }) because the plugin is initialized already
    $(id).overlayScrollbars({ resize : "both" });

Multiple elements
The initialization for multiple elements works like the initialization for a single element. The only difference is, that the initialization method will return an array of instances.

    //initialize plugin with custom options on all div elements and return all instances as array
    var instances = $("div").overlayScrollbars({ }).overlayScrollbars();

If you need the instances of multiple elements you can do it the same way as for a single element:

    //get the instance information of all elements on your page and store it into a variable
    //the array can contain undefined entries
    var instances = $("*").overlayScrollbars();

    $.each(instances, function(index, instance) {
        //check for validity
        if(instance !== undefined) {
            //do domething with the instance
        }
    });

I've built-in a filtering possibility, if you want an array only with not undefined instances:
This will only work if the jQuery selectors targets more than one element.

    //returns a array with all instances which are not undefined
    var instances = $("*").overlayScrollbars("!");

    $.each(instances, function(index, instance) {
        //do domething with the instance
    });

Since `v1.6.0` you can pass a custom filtering function.
This function has to return a boolean and takes two arguments:
The first argument is called element. This is the current HTMLElement which gets checked.
The second argument is called instance. This is the OverlayScrollbars instance of the current element which gets checked.

    //returns a array with all instances which are not undefined and applied to a div-tag-element
    var instances = $("*").overlayScrollbars(function(element, instance) {
        return element.tagName === 'DIV' && instance !== undefined;
    });

    for(var i = 0; i < instances.length; i++) {
        //do something with the instance
    }

Initialize with Extensions `added in v1.5.0`
The initialization with extensions provides a possibility to initialize your instance with one or multiple extensions.
You simply have to pass a second argument which has to be a string, an array of strings or an object. This argument represents the extensions which shall be added right after the initialization is complete.
Lets make some examples:

    //register a extension with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });
    //register a 2nd extension with the name "myOtherExtension"
    OverlayScrollbars.extension("myOtherExtension", function() { return { }; });

    //initialize the plugin with just one extension via string
    $(id).overlayScrollbars({ }, "myExtension");

    //initialize the plugin with multiple extensions via array of strings
    $(id).overlayScrollbars({ }, [ "myExtension", "myOtherExtension" ]);

    //initialize the plugin with extensions with custom options via object
    $(id).overlayScrollbars({ }, {
        "myExtension"      : { /* options for "myExtension" */ },
        "myOtherExtension" : { /* options for "myOtherExtension" */ },
    });

Options Method
Description
Returns or sets the options of the instance.
Signatures
.options()
Returns the instance options.
Returns:

Type: PlainObject

The current options of the instance.

.options(optionName)
Returns the option value with the given name.
Parameters:

optionName

Type: string

A string which represents the option whose value shall be returned.
Returns:

Type: *

The value of the options with the given name.
examples:

    var className   = instance.options("className");
    var visibility  = instance.options("scrollbars.visibility");

.options(newOptions)
Sets the instance options via a plain object.
Parameters:

newOptions

Type: PlainObject

A plain object which represents the new options.
All option possibilities can be read in the Options section tab.
examples:

    instance.options({ className : null });

.options(optionName, optionValue)
Assigns the given value to the given option Name.
Parameters:

optionName

Type: string

A string which represents the option that shall be assigned.

optionValue

Type: *

The value which shall be assigned to the given options name.
examples:

    instance.options("contentClipAlways", true);
    instance.options("overflowBehavior.y", "hidden");

Update Method
Description
Updates the instance.
Use this method to reset the "sleep" behavior of the sleep method or use it to update the instance manually.
Signatures
.update([force])
Updates the instance and resets the "sleep" behavior.
Parameters:

force

Type: boolean

A optional parameter, the default value is false.
If set to true, the plugin will be forced to do a complete update which is more expensive but guarantees a lackless update, else a normal update will be done where only necessary components are updated.
Usually (99.9%) a normal update should be enough, but ideally you will call this method only to reset the sleep behavior and never to update it manually.
If you have to call this method to update the instance manually (because else the appearance is wrong) it could be a bug, in this case please open a issue on github with a small demo.
example:

    //initialize the plugin and get its instance
    var instance = OverlayScrollbars(document.getElementById(id), { });

    //put the instance to sleep
    instance.sleep();

    //... later
    //wake the instance up so it work properly again
    instance.update();

Sleep Method
Description
Disables every observation of the DOM and puts the instance to "sleep".
It won't respond to any changes in the DOM and won't update. Scrollbars won't respond to mouse or touch events.
Resizing isn't possible anymore.
This behavior can be reset by calling the update method.
Use this method before expensive DOM operations (such as animations) to make sure the plugin won't slow them down unnecessary.
Dont forget to re-enable it after the operations via the update method.
Signatures
.sleep()
Puts the instance to sleep. It won't respond to any changes in the DOM and won't update.
example:

    //initialize the plugin and get its instance
    var instance = OverlayScrollbars(document.getElementById(id), { });

    //put the instance to sleep
    instance.sleep();

Scroll Method
Description
Returns the scroll information or sets the scroll position.
Signatures
.scroll()
Returns the current scroll information.
Returns:

Type: PlainObject

The current scroll information of the instance:
PlainObject documentaton:
Structure:

    {
        position : {
            x : number,
            y : number
        },
        ratio : {
            x : number,
            y : number
        },
        max : {
            x : number,
            y : number
        },
        handleOffset : {
            x : number,
            y : number
        },
        handleLength : {
            x : number,
            y : number
        },
        handleLengthRatio : {
            x : number,
            y : number
        },
        trackLength : {
            x : number,
            y : number
        },
        snappedHandleOffset : {
            x : number,
            y : number
        },
        isRTL           : boolean,
        isRTLNormalized : boolean
    }

Description:
position.x
The current x-axis scroll position in pixels. (scrollLeft equivalent)
position.y
The current y-axis scroll position in pixels. (scrollTop equivalent)
ratio.x
The current x-axis scroll position in percent. (Number between 0 and 1)
ratio.y
The current y-axis scroll position in percent. (Number between 0 and 1)
max.x
The max scroll position of the x-axis in pixels.
max.y
The max scroll position of the y-axis in pixels.
handleOffset.x
The handle offset of the horizontal scrollbar in pixels.
handleOffset.y
The handle offset of the vertical scrollbar in pixel.
handleLength.x
The handle length of the horizontal scrollbar in pixel.
handleLength.y
The handle length of the vertical scrollbar in pixel.
handleLengthRatio.x
The handle length of the horizontal scrollbar in percent. (Number between 0 and 1)
handleLengthRatio.y
The handle length of the vertical scrollbar in percent. (Number between 0 and 1)
trackLength.x
The track length of the horizontal scrollbar in pixels.
trackLength.y
The track length of the vertical scrollbar in pixels.
snappedHandleOffset.x
`added in v1.7.0` The snapped handle offset of the horizontal scrollbar in pixels.
If you use CSS Scroll snapping some browsers, like Google Chrome, will snap the scrollbar handle to the next possible position. By default the unsnapped (normal) handleOffset will be used, but you can change this behavior with the `scrollbars.snapHandle` option.
snappedHandleOffset.y
`added in v1.7.0` The snapped handle offset of the vertical scrollbar in pixels.
If you use CSS Scroll snapping some browsers, like Google Chrome, will snap the scrollbar handle to the next possible position. By default the unsnapped (normal) handleOffset will be used, but you can change this behavior with the `scrollbars.snapHandle` option.
isRTL
Indicates whether the values are rtl values.
isRTLNormalized
Indicates whether rtl values are normalized.
`deprecated since v1.6.0 & removed since v1.7.0`
Structure:

    {
        x : {
            position          : number,
            ratio             : number,
            max               : number,
            handleOffset      : number,
            handleLength      : number,
            handleLengthRatio : number,
            trackLength       : number,
            isRTL             : boolean
            isRTLNormalized   : boolean
        },
        y : {
            position          : number,
            ratio             : number,
            max               : number,
            handleOffset      : number,
            handleLength      : number,
            handleLengthRatio : number,
            trackLength       : number
        }
    }

Description:
x.position
The current x-axis scroll position in pixels. (scrollLeft equivalent)
x.ratio
The current x-axis scroll position in percent. (Number between 0 and 1)
x.max
The max scroll position of the x-axis in pixels.
x.handleOffset
The handle offset of the horizontal scrollbar in pixels.
x.handleLength
The handle length of the horizontal scrollbar in pixels.
x.handleLengthRatio
The handle length of the horizontal scrollbar in percent. (Number between 0 and 1)
x.trackLength
The track length of the horizontal scrollbar in pixels.
x.isRTL
Indicates whether the values are rtl values.
x.isRTLNormalized
Indicates whether rtl values are normalized.
y.position
The current y-axis scroll position in pixels. (scrollTop equivalent)
y.ratio
The current y-axis scroll position in percent. (Number between 0 and 1)
y.max
The max scroll position of the y-axis in pixel.
y.handleOffset
The handle offset of the vertical scrollbar in pixels.
y.handleLength
The handle length of the vertical scrollbar in pixels.
y.handleLengthRatio
The handle length of the vertical scrollbar in percent. (Number between 0 and 1)
y.trackLength
The track length of the vertical scrollbar in pixels.
.scroll(coordinates [, duration] [, easing] [, complete])
Sets the scroll position.
Parameters:

coordinates

Type: *

The coordinates describes the new scroll position.
Coordinates contain the position value(s) for the x- and y-axis.
A position value can be a number or a string.
If you specify your position as a string, you have the following possibilities:
Position operators:
A position can have one operator in front.
The following operators are supported:
"+="
The position value will be added to the current scroll-offset.
"-="
The position value will be subtracted from the current scroll-offset.
"*="
The current scroll-offset will be multiplicated by the position value.
"/="
The current scroll-offset will be divided by the position value.
Position units:
Each number can be followed by a unit.
The following units are supported:
"px"
Same as no unit.
value = (value * 1)
"%"
The value is dependent on the current scroll value.
value = ((currentScrollOffset / 100) * value)
"vw"
The value is multiplied by the viewport-width of the host-element.
value = (value * viewportWidth)
"vh"
The value is multiplied by the viewport-height of the host-element.
value = (value * viewportHeight)
Examples
It's also possible to calculate a position.
Here are a few examples:

    //scrolls the y-axis to 100% -> to the bottom.
    instance.scroll({ y : "100%"  });

    //scrolls the y-axis to 50%. You could write 50% directly, but I want to demonstrate the calculation possibility.
    instance.scroll({ y : "100% / 2"  });

    //calculates the final result and then adds it to the current y-axis scroll-offset.
    instance.scroll({ y : "+= 10% - 25"  });

    //subtracts 50 pixel from the currext y-axis scroll-offset.
    instance.scroll({ y : "-= 50px"  });

Coordinates can be specified in different ways. Here is a overview of all possibilities.
A PlainObject which contains the new scroll position:
The PlainObject describes the coordinates. `instance.scroll({ x : position, y : position });
//or
instance.scroll({ l : position, t : position });
//or
instance.scroll({ left : position, top : position });
`
A array which contains the new scroll position:
The array describes the coordinates. The first value stands for the x-axis and the second value stands for the y-axis. `//[ x, y ]
instance.scroll([ position, position ]);
`
A position which affects both axis:
The position value describes the coordinates for both axis. `instance.scroll(position);
`
A HTML or jQuery Element:
The top offset of the element stands for the y-axis scroll value and the left offset of the element stand for the x-axis scroll value. `instance.scroll($(selector));
//or
instance.scroll(document.getElementById("id"));
`
A HTML or jQuery Element with additional settings:
To use this approach a PlainObject with the following structure must be passed:

    {
        el       : HTMLElement | jQueryElement,
        scroll   : string | array | object,
        block    : string | array | object,
        margin   : number | boolean | array | object
    }

PlainObject description:
el
The HTML or jQuery Element which shall describe the coordinates.
MUST be specified or else this object isn't valid and this approach won't work.
scroll `added in v1.5.0`
The scroll behavior which shall be used. The Default value is "always".
Possible values are:
"always"
Scrolls always.
"ifneeded"
Scrolls only if the element isn't fully in view.
Implemented in order to support: Element.scrollIntoViewIfNeeded().
"never"
Scrolls never.
array
With this array you are able to specify the scroll strategy for each axis individually.
A example: `[ "never", "always" ]` - with this array a scroll will be performed only on the y-axis.
object
The passed object specifies the scroll strategy for each axis with its properties `x` and `y`. If your object doesn't specify a value for a axis, it's treated as if the value was `always`.
A example object would look like: `{ x : "never" }`
block
The edge which shall be docked to the viewport. The Default value is "begin".
Possible values are:
"begin"
Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
"end"
Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
"center"
The element gets centered horizontally and vertically.
"nearest"
The element gets docked to the nearest edge(s).
array
With this array you are able to specify the edge for each axis individually.
If the direction is RTL, the x-axis values are inverted ("begin" = dock to right, "end" = dock to left).
A example: `[ "begin", "end" ]` - with this array the element will be docked to the left and bottom edge of the viewport.
A second example: `[ "center", "begin" ]` - with this array the element will be docked to the top edge of the viewport and is centered horizontally.
object
`added in v1.5.0`
The passed object specifies the block for each axis with its properties `x` and `y`. If your object doesn't specify a value for an axis, it's treated as if the value was `begin`.
A example object would look like: `{ y : "center" }`
margin
The margin which shall be used. The Default value is false.
The original CSS margin won't be affected.
Possible values are:
true
The true CSS margin of the element will be used.
false
No margin will be used, even if the element has CSS margin.
number
The specified number will be used as margin for all directions.
array
The passed array can have the size of two or the size of four.
A array with two entries specifies the margin for the left&right and top&bottom directions:
`[ left&right, top&bottom ]`
A array with four entries specifies the margin for all directions:
`[ top, right, bottom, left ]` The array can consist of numbers or booleans or a mix.
A example array would look like: `[ true, 0, 0, 10 ]`
object
`added in v1.5.0`
The passed object specifies the margin with the properties called `top`, `right`, `bottom` and `left`. The values can be booleans (if the original CSS margin value of the corresponding direction shall be used) or numbers (if a custom margin value shall be used).
If your object doesn't specify a value for a direction, it's treated as if the value was `0`.
A example object would look like: `{ top : true, left: 10 }`
axis `deprecated since v1.5.0`
This property is deprecated. Please use the new "scroll" property instead!
Old documentation:
The axis which shall be scrolled. The Default value is "xy".
Possible values are:
"xy"
Scrolls both axis.
"yx"
Scrolls both axis.
"x"
Scrolls only the x-axis.
"y"
Scrolls only the y-axis.

duration

Type: number

The duration in milliseconds of the scroll-animation.

easing

Type: string | array | object

The easing of the scroll-animation.
A single string represents the easing for both axis.
If you pass a array, the first entry is the easing for the x axis and the second entry is the easing for the y axis.
`added in v1.6.0`
If you pass a object, the x property represents the easing for the x axis and the y property represents the easing for the y axis.
If undefined the easing is "swing".

complete

Type: function

The callback function which shall be called after the scroll-animation has completed.
examples:

    //set the scroll-offset to 50 on both axis.
    instance.scroll(50);

    //scroll to 50% on both axis with a duration of 1000ms
    instance.scroll({ x : "50%", y : "50%" }, 1000);

    //scroll to 0 on the x-axis and to 100% on the y-axis with a duration of 2500ms
    instance.scroll([ 0, "100%" ], 2500);

    //scroll to 50% on both axis with a duration of 5500ms
    //use a "linear" easing on the x axis and a "easeOutBounce" easing on the y axis
    instance.scroll("50%", 5500, { x : "linear", y : "easeOutBounce" });

    //set the x-axis scroll-offset to 0 and add a calculatd value to the y-axis scroll-offset
    //with a duration of 1500ms
    //with a "easeOutBounce" easing for both axis
    instance.scroll({ x : 0, y : "+= 30% - 25px" }, 1500, "easeOutBounce");

    //subtract 10 pixel from the current x-axis scroll-offset and set the y-axis scroll-offset to 10 pixel
    instance.scroll({ x : "-= 10px", y : 10 });

    //scroll to the left top corner of the passed element
    instance.scroll(element);

    //scroll to the left top corner of the passed element
    //with a duration of 1300ms
    //with no easing
    //with a complete callback
    instance.scroll(element, 1300, undefined, function() { });

    //equivalent of the scrollIntoView() method
    instance.scroll({ el : element, block : { y : "begin", x : "nearest" } });

    //equivalent of the scrollIntoView(false) method
    instance.scroll({ el : element, block : { y : "end", x : "nearest" } });

    //scroll to the top edge of the passed element if it isn't in view
    //with 500ms
    instance.scroll({ el : element, scroll : { y : "ifneeded", x : "never" } }, 500);

    //scroll to the bottom edge of the passed element
    instance.scroll({ el : element, scroll : { x : "never" }, block : "end" });

    //scroll to the bottom and left edge of the passed element if it isnt in view and let 10 pixel margin
    instance.scroll({ el : element, scroll : "ifneeded", block : ["begin", "end"], margin : 10 });

.scroll(coordinates, options)
Sets the scroll position.
Parameters:

coordinates

Type: *

Read the documentation of this parameter above. They are alike.

options

Type: PlainObject

A jQuery animate options object. Read more
ScrollStop Method
Description
Stops the current scroll-animation.
Signatures
.scrollStop()
Stops the current scroll-animation.
Has the same paramets as the jQuery.stop() method. Read more
Returns: `added in v1.5.0`

Type: OverlayScrollbars

The current OverlayScrollbars instance, so you can chain this method with other methods.
example:

    //scroll-animation duration is 10 seconds
    instance.scroll({ y : "100%" }, 10000);

    //abort the 10 seconds scroll-animation immediately
    instance.scrollStop();

    //scroll-animation duration is 1 second
    instance.scroll({ y : "100%" }, 1000);

    //chaining added in v1.5.0 - stop the old animation and start a new one in one line
    instance.scrollStop().scroll({ y : 500 }, 5000);

GetElements Method
Description
Returns all relevant elements.
Signatures
.getElements()
Returns all relevant elements.
Returns:

Type: PlainObject

Structure:

    {
        target   : HTMLElement,
        host     : HTMLElement,
        padding  : HTMLElement,
        viewport : HTMLElement,
        content  : HTMLElement,
        scrollbarHorizontal : {
            scrollbar : HTMLElement,
            track     : HTMLElement,
            handle    : HTMLElement
        },
        scrollbarVertical : {
            scrollbar : HTMLElement,
            track     : HTMLElement,
            handle    : HTMLElement
        },
        scrollbarCorner : HTMLElement
    }

Description:
target
The target element. - The element to which this instance was attached to.
host
The host element. - The element which is the topmost element of the instance.
padding
The padding element. - This element controls the padding.
viewport
The viewport element. - This element responsible for the native scrolling.
content
The content element. - Contains all the content which shall be scrolled.
scrollbarHorizontal.scrollbar
The horizontal scrollbar element. - The topmost horizontal scrollbar element.
scrollbarHorizontal.track
The horizontal scrollbar track element. - The track of the horizontal scrollbar.
Is the parent of the handle element.
scrollbarHorizontal.handle
The horizontal scrollbar handle element. - The handle of the horizontal scrollbars.
This element could contain custom content.
scrollbarVertical.scrollbar
The vertical scrollbar element. - The topmost vertical scrollbar element.
scrollbarVertical.track
The vertical scrollbar track element. - The track of the vertical scrollbar.
Is the parent of the handle element.
scrollbarVertical.handle
The vertical scrollbar handle element. - The handle of the vertical scrollbars.
This element could contain custom content.
scrollbarCorner
The scrollbar corner element. Is the corner which appears if both scrollbars are visible.
Is also the resize handle.
.getElements(elementName)
Returns the element with the given name.
Parameters:

elementName

Type: string

The name of the element which shall be returned.
Returns:

Type: *

The value of the given element name.
examples:

    var host               = instance.getElements("host");
    var horizontalHandle   = instance.getElements("scrollbarHorizontal.handle");
    var verticalHandle     = instance.getElements("scrollbarVertical.handle");

GetState Method
Description
Returns a object which describes the current state of this instance.
Signatures
.getState()
Returns a object which describes the current state of this instance.
Returns:

Type: PlainObject

Structure:

    {
        destroyed     : boolean,
        sleeping      : boolean,
        autoUpdate    : boolean,
        widthAuto     : boolean,
        heightAuto    : boolean,
        documentMixed : boolean,
        padding : {
            t : number,
            r : number,
            b : number,
            l : number
        },
        overflowAmount : {
            x : number,
            y : number
        },
        hideOverflow : {
            x  : boolean,
            y  : boolean,
            xs : boolean,
            ys : boolean
        },
        hasOverflow : {
            x : boolean,
            y : boolean
        },
        contentScrollSize : {
            width  : number,
            height : number
        },
        viewportSize : {
            width  : number,
            height : number
        },
        hostSize : {
            width  : number,
            height : number
        }
    }

Description:
destroyed
Indicates whether this instance is destroyed. `added in v1.8.0`
sleeping
Indicates whether this instance is currently sleeping due to the sleep method.
autoUpdate
Indicates whether this instance uses the autoUpdateLoop.
widthAuto
Indicates whether the host-element's width is auto.
heightAuto
Indicates whether the host-element's height is auto.
documentMixed
Indicates whether the host-elements document isn't the same document as the one with which the plugin was initialized. If this property is true it's most likely the host-element is inside an iFrame. `added in v1.4.5`
padding.t
The top padding of the host-element in pixel.
padding.r
The right padding of the host-element in pixel.
padding.b
The bottom padding of the host-element in pixel.
padding.l
The left padding of the host-element in pixel.
overflowAmount.x
The overflow amount of the x-axis in pixel.
overflowAmount.y
The overflow amount of the y-axis in pixel.
hideOverflow.x
Indicates whether the overflow on the x-axis is hidden by `overflow-x: hidden` or `overflow-x: scroll`.
hideOverflow.y
Indicates whether the overflow on the y-axis is hidden by `overflow-y: hidden` or `overflow-y: scroll`.
hideOverflow.xs
Indicates whether the overflow on the x-axis is hidden by `overflow-x: scroll`.
hideOverflow.ys
Indicates whether the overflow on the y-axis is hidden by `overflow-y: scroll`.
hasOverflow.x
Indicates whether the x-axis has an overflow. (overflowAmount.x > 0)
hasOverflow.y
Indicates whether the y-axis has an overflow. (overflowAmount.y > 0)
contentScrollSize.width
The width of the scrollable content in pixels.
contentScrollSize.height
The height of the scrollable content in pixels.
viewportSize.width
The width of the viewport in pixels.
viewportSize.height
The height of the viewport in pixels.
hostSize.width
The width of the host-element in pixels.
hostSize.height
The height of the host-element in pixels.
.getState(stateProperty)
Returns the value of the given state property.
Parameters:

stateProperty

Type: string

A string which represents a property of the state object.
Returns:

Type: *

The value of the given state property.
examples:

    var isWidthAuto          = instance.getState("widthAuto");
    var contentScrollHeight  = instance.getState("contentScrollSize.height");

Destroy Method
Description
Destroys and disposes the current instance and removes all extensions and added elements from the DOM.
Signatures
.destroy()
Destroys the current instance and resets the DOM of the target-element to the state before the initialization.
example:

    //initialize the plugin and get its instance
    var instance = OverlayScrollbars(document.getElementById(id), { });

    //destroy the instance
    instance.destroy();

    //try to get the instance of the plugin again, but it's undefined
    instance = var instance = OverlayScrollbars(document.getElementById(id));

Ext Method
Description
Returns the instance of a certain extension of the current plugin instance. `added in v1.5.0`
Signatures
.ext( extensionName )
Returns the instance of a previously added extension with the given name.
Parameters:

extensionName

Type: string

The name of the previously added extension of which the instance shall be got.
Returns:

Type: PlainObject | undefined

The instance of the extension with the given name or undefined if no instance was found.
This instance is just a copy of the actual instance. Changes to this object won't affect the original instance.
example:

    //register a dummy extensions with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });

    //initialize the plugin with the extension "myExtension" and get the plugins instance
    var instance = OverlayScrollbars(document.getElementById(id), { }, "myExtension");

    //get the instance of the extension "myExtension"
    var extensionInstance = instance.ext("myExtension");

.ext()
Gets a object which contains all instances of all extensions which has been added to the current instance.
Returns:

Type: PlainObject

The object keys represent the names of the added extensions. The corresponding values represent the instances.
All instance objects are just a copy and changes won't affect the original instance.
If a instance has no extensions added, a empty object will be returned.
AddExt Method
Description
Adds a extension to the current instance. `added in v1.5.0`
Signatures
.addExt( extensionName [, options] )
Adds a previously registered extension with the given name to the plugin instance and returns the instance of the extension or undefined if the extension couldn't be added.
Parameters:

extensionName

Type: string

The name of the extension which shall be added to the instance.

options

Type: *

A optional parameter.
Options with which the extension shall be added.
Options can be of any type, but I highly recommend using an object.
Returns:

Type: PlainObject | undefined

The instance of the added extension or undefined if the extension wasn't added successfully.
This instance is just a copy of the actual instance. Changes to this object won't affect the original instance.
example:

    //register a dummy extensions with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });

    //initialize the plugin and get its instance
    var instance = OverlayScrollbars(document.getElementById(id), { });

    //add the previously registered extension "myExtension" to the plugin instance
    var extensionInstance = instance.addExt("myExtension");

RemoveExt Method
Description
Removes an extension from the current instance. `added in v1.5.0`
Signatures
.removeExt( extensionName )
Removes a previously added extension from the current instance and returns a boolean which indicates whether the removal was successful.
Parameters:

extensionName

Type: string

The name of the previously added extension which shall be removed.
Returns:

Type: boolean

True if the extension was successfully removed, false otherwise (for example if the extension wasn't added before).
example:

    //register a dummy extension with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });

    //initialize the plugin and get its instance
    var instance = OverlayScrollbars(document.getElementById(id), { });

    //add the previously registered extension "myExtension" to the plugin instance
    instance.addExt("myExtension");

    //remove the previously added extension "myExtension" from the plugin instance
    instance.removeExt("myExtension");

OverlayScrollbars.defaultOptions Method
Description
Returns or Sets the default options for each new plugin initialization.
Signatures
OverlayScrollbars.defaultOptions()
Returns the default options object.
Returns:

Type: PlainObject

The object which describes the defaultOptions.

examples:

    //Gets the current defaultOptions
    var defaultOptions = OverlayScrollbars.defaultOptions();

OverlayScrollbars.defaultOptions(newDefaultOptions)
Sets the default options via a plain object.
Parameters:

newDefaultOptions

Type: PlainObject

A plain object which represents the new default options.
All option possibilities can be read in the Options section.
examples:

    //this instance has the default defaultOptions.
    OverlayScrollbars(document.getElementById(id), { });

    OverlayScrollbars.defaultOptions({
        className : "my-custom-class",
        resize    : "both"
    });

    //this instance has the new defaultOptions, which means the options:
    //className = "my-custom-class"
    //resize = "both"
    //are set automatically even without custom options in the constructor
    OverlayScrollbars(document.getElementById(otherId), { });

OverlayScrollbars.globals Method
Description
Returns a plain object which contains global information about the plugin and each instance of it.
Signatures
OverlayScrollbars.globals()
Returns a object which contains global information about the plugin and each instance of it.
The purpose of this method is to provide access to all information which the plugin is able to offer.
Returns:

Type: PlainObject

The returned plain object is just a copy, which means that changes to the returned object won't have any effect to the original object.
Structure:

    {
        defaultOptions          : PlainObject,
        autoUpdateLoop          : boolean,
        autoUpdateRecommended   : boolean,
        supportMutationObserver : boolean,
        supportResizeObserver   : boolean,
        supportPassiveEvents    : boolean,
        supportTransform        : boolean,
        supportTransition       : boolean,
        restrictedMeasuring     : boolean,
        nativeScrollbarStyling  : boolean,
        nativeScrollbarSize : {
            x : number,
            y : number
        },
        nativeScrollbarIsOverlaid : {
            x : boolean,
            y : boolean
        },
        overlayScrollbarDummySize : {
            x : number,
            y : number
        },
        rtlScrollBehavior : {
            i : boolean,
            n : boolean
        }
    }

Description:
defaultOptions
The default options for each new plugin initialization. This is the same object as the returned object from the `OverlayScrollbars.defaultOptions()` function.
autoUpdateLoop
Indicates whether the auto update loop is running or not.
autoUpdateRecommended
Indicates whether the auto update loop is recommended for your browser.
If the option `autoUpdate` is null and this property returns true, you can be sure that your instance is updating due to the update loop.
This property should be only true in old browsers.
supportMutationObserver
Indicates whether your browser is capable of the MutationObserver API.
supportResizeObserver
Indicates whether your browser is capable of the ResizeObserver API.
supportPassiveEvents
Indicates whether your browser is capable of passive event listeners.
supportTransform
Indicates whether your browser is supporting CSS3 Transforms.
supportTransition
Indicates whether your browser is supporting CSS3 Transitions.
restrictedMeasuring
Indicates whether the scrollSize calculation is only correct if certain CSS properties are set. More info.
nativeScrollbarStyling
Indicates whether your browser is capable of styling (hiding) the scrollbar via a CSS Pseudo Element or CSS Property.
nativeScrollbarSize.x
The height of the native horizontal scrollbar.
nativeScrollbarSize.y
The width of the native vertical scrollbar.
nativeScrollbarIsOverlaid.x
Indicates whether the native horizontal scrollbar is overlaid. (nativeScrollbarSize.x === 0)
nativeScrollbarIsOverlaid.y
Indicates whether the native vertical scrollbar is overlaid. (nativeScrollbarSize.y === 0)
overlayScrollbarDummySize.x
Well, an explanation would be very long and require know how about the plugin so just ignore this property.
overlayScrollbarDummySize.y
Well, an explanation would be very long and require know how about the plugin so just ignore this property.
rtlScrollBehavior.i
Indicates whether the origin side is wrong.
The origin side should be the right side if you set your direction to "right to left" (rtl).
This is not specified anywhere so browsers are handling this differently.
"i" is shorthand for "invert" - we need to invert the origin side to normalize RTL scroll.
rtlScrollBehavior.n
Indicates whether the scrollLeft maximum value is negative.
The scrollLeft offset should be always positive. Normally the range for this value is from zero (0) to a positive value which respresents the maximum scrollLeft offset.
But if you set your direction to "right to left" (rtl), it can be that the scrollLeft offset goes from (0) to a negative value which respresents the maximum scrollLeft offset.
This is not specified anywhere so browsers are handling this differently.
"n" is shorthand for "negate" - we need to negate the scrollLeft offset to normalize RTL scroll.
cssCalc
`deprecated since v1.12.0`
The name for the CSS calc function (with vendor prefix) or null if the CSS calc function is not supported.
examples:

    //returns a object which represents global infromation about the plugin
    var globals = OverlayScrollbars.globals();

OverlayScrollbars.extension Method
Description
Registers, Unregisters or returns extensions. `added in v1.5.0`
Signatures
OverlayScrollbars.extension( extensionName, extensionFactory [, defaultOptions] )
Registers a extension globally to the plugin, so it can be used by instances.
Parameters:

extensionName

Type: string

A string which represents the name of the extension which shall be registered.

extensionFactory

Type: function

A function which returns the instance of your extension.
It takes three arguments which are described in more detail in this section.

defaultOptions

Type: *

A optional parameter.
If the extension is complex and offers a possibility to manage options, you can pass default options with this parameter.
Options can be of any type, but I highly recommend using an object.
examples:

    //register a dummy extension with the name "myExtension"
    OverlayScrollbars.extension("myExtension", function() { return { }; });

OverlayScrollbars.extension( extensionName, extensionFactory )
Unregisters a extension globally from the plugin.
Parameters:

extensionName

Type: string

The name of the previous registered extension.

extensionFactory

Type: null | undefined

You can pass anything here, as long as it is no function the extension with the given name will be unregistered.
I suggest to pass null or undefined.
examples:

    //unregister the extension with the name "myExtension"
    OverlayScrollbars.extension("myExtension", null);

OverlayScrollbars.extension( extensionName )
Returns the extension-object of the extensions with the given name.
Parameters:

extensionName

Type: string

The name of the previous registered extension, of which the extension-object shall be returned.
Returns:

Type: PlainObject

The returned plain object is just a copy, which means that changes to the returned object won't have any effect to the original object.
Structure:

    {
        name             : string,
        extensionFactory : function,
        defaultOptions   : object | undefined
    }

Description:
name
The name with which the extension was registered.
extensionFactory
The function which returns the instance of your extension.
defaultOptions
The default options object of your extension or undefined if you haven't passed any.
examples:

    //get the extension-object with the name "myExtension"
    var registeredExtension = OverlayScrollbars.extension("myExtension");

OverlayScrollbars.extension()
Returns an array like object which contains all extension-objects which has been registered.
Returns:

Type: ArrayLikeObject

The returned object is just a copy, which means that changes to the returned object won't have any effect to the original object.
examples:

    var extensionObjects = OverlayScrollbars.extension(); //get all registered extension-objects
    var registeredExtensionCount = extensionObjects.length; //get the number of registered extensions
    var firstRegisteredExtensionObject = extensionObjects[0]; //get the first registered extension-object

OverlayScrollbars.valid Method
Description
Checks whether a passed object is a non-destroyed OverlayScrollbars instance. `added in v1.9.0`
Signatures
OverlayScrollbars.valid(osInstance)
Checks whether the passed object is a non-destroyed OverlayScrollbars instance.
Parameters:

osInstance

Type: *

The potential OverlayScrollbars instance which shall be checked.
examples:

    //create OverlayScrollbars instance
    var osInstance = OverlayScrollbars(document.body, { });

    //returns true
    OverlayScrollbars.valid(osInstance);

    //destroy the instance
    osInstance.destroy();

    //returns false
    OverlayScrollbars.valid(osInstance);

    //returns false
    OverlayScrollbars.valid({ });

Extensions
The extension system was `added in v1.5.0`.
Since each app has its own environment with its own requirements, it is impossible to cover all edge-cases within the standard features.
Extensions provides a simple and elegant way to implement non-standard features into OverlayScrollbars.
Lifecycle
A extension can be added right at the initialization of a OverlayScrollbars instance or with the addExt method of a OverlayScrollbars instance. To remove a extension you have two possibilities. You can do it via the removeExt method or you can destroy the OverlayScrollbars instance. This will remove all extensions.
Interface
A extensionFactory is basically a function which is returning a object. This object is the instance of your extension.
The most simple extension would look like this:

    var extensionFactory = function() {
        return { }; //<- this is the actual extension
    };

In order to make it more simple and comfortable for developers, the function has a bunch of parameters which make the development much easier. Furthermore the `this`-context of the extensionFactory function is the OverlayScrollbars instance which is trying to add the extension.

    var extensionFactory = function(defaultOptions, framework, compatibility) {
        var osInstance = this;
        return { }; //<- this is the actual extension
    };

Parameter | Description
defaultOptions | The "defaultOptions" value which were passed to the global extension method in order to register this extension. If no defaultOptions value was passed this parameter is undefined.

framework

The framework which OverlayScrollbars is using internally in order to make it simpler to manipulate and traverse the DOM. If the jQuery version is used, this parameter is the jQuery object. However, if the non-jQuery version is used, this parameter is a jQuery-like-object which has the same API-structure as jQuery but doesn't offer all its functionality. A documentation of the supported methods can be found here.

compatibility | A object which offers compatibility methods. These methods are unifying native methods which are different or not present across all browsers. (for example if methods or objects have vendor prefixes, different names or signatures and so on...) A documentation of all methods can be found here.

Special methods
You are free to design your extension instance as you like.
However, every extension can have 4 methods which interact directly with the OverlayScrollbars instance. These methods have fixed (reserved) names and they are only called from the OverlayScrollbars instance itself. They can't be called from the outside.
The names of these methods are:

Method Name | Description

contract

Gets called if an instance tries to add an extension.
Use this method to determine whether the extension can be added or not. With this method you have the opportunity to abort the adding process.
This method has to return a boolean, if the method returns any other type, the method will be ignored.
If the method returns true the extension will be added, if it returns false the extension won't be added.
If your extension doesn't have a contract method the extension will be added always.
The method has one parameter:
global : The global object of OverlayScrollbars. (The global window object)

added | Gets called once the extension was successfully added to a OverlayScrollbars instance. Use this method to add all your functionality, DOM elements and so on. The method has one parameter: options : The custom options which have been passed to the extension. This parameter is optional and can be undefined if no options were passed.
removed | Gets called once the extension was removed from a OverlayScrollbars instance. Use this method to remove all your added functionality, DOM elements and so on. The method has no parameters.
on | Gets called after a event happened. The method has two parameters: callbackName : The callback name as specified in the options but without the prefix "on". For exampple the if the event `onOverflowChanged` happened this parameter is `overflowChanged`. callbackArgs : The corresponding callback argument. A documentation of all callback arguments can be read here.

A small code example:

    var extensionFactory = function(defaultOptions, compatibility, framework) {
        var osInstance = this;
        var extension = { };

        //the reserved "contract" method, can't be called freely
        extension.contract = function(global) { /* code... */ }

        //the reserved "added" method, can't be called freely
        extension.added = function(options) { /* code... */ };

        //the reserved "removed" method, can't be called freely
        extension.removed = function() { /* code... */ };

        //the reserved "on" method, can't be called freely
        extension.on = function(callbackName, callbackArgs) { /* code... */ };

        //a custom method which can be called freely
        extension.myCustomMethod = function() { /* code... */ };

        return extension;
    };

Epilogue
I've designed the extension system to be simple and powerful at the same time. However if you're missing any features please open an issue on github and make your suggestion.
Create Extensions
The extension system was `added in v1.5.0`.
Before you read this section, please make sure you've read and understand the extension basics.
This section is here to show example templates which shall illustrate how you write an extension correctly.
Examples
Basic Extension
This extension adds a red div to the handles of the scrollbars.

    OverlayScrollbars.extension("myBasicExtension", function(defaultOptions, framework, compatibility) {
        var osInstance = this;
        var extension = { };

        var handleElmHorizontal;
        var handleElmVertical;

        extension.added = function() {
            var instanceElements = osInstance.getElements();
            var scrollbarHorizontalHandle = instanceElements.scrollbarHorizontal.handle;
            var scrollbarVerticalHandle = instanceElements.scrollbarVertical.handle;
            var html = '<div style="height: 100%; width: 100%; background: red;"></div>';

            handleElmHorizontal = framework(html);
            handleElmVertical = framework(html);

            framework(scrollbarHorizontalHandle).append(handleElmHorizontal);
            framework(scrollbarVerticalHandle).append(handleElmVertical);
        }

        extension.removed = function() {
            handleElmHorizontal.remove();
            handleElmVertical.remove();
        }

        return extension;
    });

Test this extension by clicking on the corresponding play button.
Errors or additional messages are displayed in the console.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
`.addExt("myBasicExtension");`
`.removeExt("myBasicExtension");`
Advanced Extension
This extension adds custom colored divs to the track of the scrollbars.
The default color is "orange", but it can be changed if you pass a valid options object with a different color to the "addExt" method.
With the custom method "changeColor" the color can be changed whenever you want.
The position and size of the custom divs gets adjusted if you scroll.

    OverlayScrollbars.extension("myAdvancedExtension", function(defaultOptions, framework, compatibility) {
        var osInstance = this;
        var extension = { };

        var trackElmHorizontal;
        var trackElmHorizontal2;
        var trackElmVertical;
        var trackElmVertical2;

        //add the divs after the extension has been added to a instance
        extension.added = function(options) {
            //extend the defaultOptions with the passed options
            //to determine the correct color
            var parsedOptions = framework.extend(true, { }, defaultOptions, options);
            var instanceElements = osInstance.getElements();
            var scrollbarHorizontalHandle = instanceElements.scrollbarHorizontal.track;
            var scrollbarVerticalHandle = instanceElements.scrollbarVertical.track;
            var html = '<div style="height: 100%; width: 100%; top: 0; left: 0; position: absolute;"></div>';
            var sInfo = osInstance.scroll();

            trackElmHorizontal = framework(html).css({
                background : parsedOptions.color,
                width : sInfo.handleOffset.x
            });
            trackElmHorizontal2 = framework(html).css({
                background : parsedOptions.color,
                width : sInfo.trackLength.x - (sInfo.handleOffset.x + sInfo.handleLength.x),
                left : sInfo.handleOffset.x + sInfo.handleLength.x
            });
            trackElmVertical = framework(html).css({
                background : parsedOptions.color,
                height : sInfo.handleOffset.y
            });
            trackElmVertical2 = framework(html).css({
                background : parsedOptions.color,
                height : sInfo.trackLength.y - (sInfo.handleOffset.y + sInfo.handleLength.y),
                top : sInfo.handleOffset.y + sInfo.handleLength.y
            });

            framework(scrollbarHorizontalHandle).append([trackElmHorizontal, trackElmHorizontal2])
            framework(scrollbarVerticalHandle).append([trackElmVertical, trackElmVertical2]);
        }

        //remove the divs after the extension has been removed from a instance
        extension.removed = function() {
            trackElmHorizontal.remove();
            trackElmHorizontal2.remove();
            trackElmVertical.remove();
            trackElmVertical2.remove();
        }

        //hide the custom divs during scrolling
        extension.on = function(callbackName, args) {
            switch(callbackName) {
                case "scroll":
                    var sInfo = osInstance.scroll();

                    trackElmHorizontal.css({
                        width : sInfo.handleOffset.x
                    });
                    trackElmHorizontal2.css({
                        width : sInfo.trackLength.x - (sInfo.handleOffset.x + sInfo.handleLength.x),
                        left : sInfo.handleOffset.x + sInfo.handleLength.x
                    });
                    trackElmVertical.css({
                        height : sInfo.handleOffset.y
                    });
                    trackElmVertical2.css({
                        height : sInfo.trackLength.y - (sInfo.handleOffset.y + sInfo.handleLength.y),
                        top : sInfo.handleOffset.y + sInfo.handleLength.y
                    });
                    break;
            }
        }

        //a custom method which changes the colors of the added divs
        extension.changeColor = function(color) {
            trackElmHorizontal.css("background", color);
            trackElmHorizontal2.css("background", color);
            trackElmVertical.css("background", color);
            trackElmVertical2.css("background", color);
        }

        return extension;
    }, { //defaultOptions:
        color : "orange"
    });

Test this extension by clicking on the corresponding play button.
Errors or additional messages are displayed in the console.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
`.addExt("myAdvancedExtension");`
`.addExt("myAdvancedExtension", { color : "DodgerBlue" });`
`.ext("myAdvancedExtension").changeColor("Crimson");`
`.ext("myAdvancedExtension").changeColor("GreenYellow");`
`.removeExt("myAdvancedExtension");`
Extension with dependencies
This extension needs jQuery to work correctly, else it won't be added to the instance.

    OverlayScrollbars.extension("myDependencyExtension", function(defaultOptions, framework, compatibility) {
        var osInstance = this;
        var extension = { };

        //determine if jQuery is available
        extension.contract = function(global) {
            return global.jQuery && global.jQuery.fn;
        }

        //write a message if this extension is added successfully
        extension.added = function() {
            console.log("The dependency extension was added successfully.");
        }

        //write a message if this extension is removed successfully
        extension.removed = function() {
            console.log("The dependency extension was removed successfully.");
        }

        return extension;
    });

Publish your Extension
If you've written your own extension and you want to make it available for everyone, please open an issue on github. After I've reviewed your extension it will be listed on the official extensions page where everyone can download it.
Built-in themes
This plugin comes with three very basic built-in themes:
"none" -theme
Use this theme if you dont want any visible scrollbars.
The "none" theme hides basically the appearance of the scrollbars.
Its class name is `.os-theme-none`. Thus it can be activated if you set the className option to this value or null.
Here is a quick demo of this theme:

    //initializes the plugin with "none" -theme
    OverlayScrollbars(document.getElementById(id), { className : null });

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
"dark" -theme
This theme is the way to go if your page has a bright background.
The "dark" theme is a very simple and clean theme with a dark touch.
It's class name is `.os-theme-dark`. Thus it can be activated if you set the className option to this value.
Here is a quick demo of this theme:

    //initializes the plugin with "dark" -theme
    OverlayScrollbars(document.getElementById(id), { className : "os-theme-dark" });

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
"light" -theme
This theme is the way to go if your page has a dark background.
The "light" theme is a very simple and clean theme with a bright touch.
It's class name is `.os-theme-light`. Thus it can be activated if you set the className option to this value.
Here is a quick demo of this theme:

    //initializes the plugin with "light" -theme
    OverlayScrollbars(document.getElementById(id), { className : "os-theme-light" });

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Class Names
The scrollbar styling is very simple if you understand the selectors and their meanings.
I've tried to use self explanatory class names.
Host Element
The plugin is adding several class names to the host-element. Some of them are always present and some are only present if a certain behavior is fulfilled. This class names helps us to understand the current state of the plugin & scrollbars.
Here is a complete listing of all class names of the host-element:
All class names for the host-element have the prefix ".os-host".

Class Name | Description
.os-host | Indicates whether this element is a host-element. Only applied if the host-element is NOT for a textarea (the target-element is NOT a textarea element).
.os-host-textarea | Indicates whether this element is a host-element for a textarea. Only applied if the host-element is for a textarea (the target-element is a textarea element).
.os-host-transition | Indicates that the plugin is fully initialized and transitions are possible now.
.os-host-rtl | Indicates whether the detected horizontal scroll direction is RTL (Right To Left).
.os-host-resize-disabled | Indicates that the resize option is set to "none".
.os-host-scrolling | Indicates that a scroll is performing right now.
.os-host-overflow | Indicates whether a overflow on any axis is present.
.os-host-overflow-x | Indicates whether a overflow on the x-axis is present.
.os-host-overflow-y | Indicates whether a overflow on the y-axis is present.
.os-host-scrollbar-horizontal-hidden | Indicates whether the horizontal scrollbar is hidden due to the "visibility" option. (If set to "hidden" this class is always applied. If set to "visible" this class is never applied. If set to "auto" this class is only applied if a overflow on the x-axis is present.)
.os-host-scrollbar-vertical-hidden | Indicates whether the vertical scrollbar is hidden due to the "visibility" option. (If set to "hidden" this class is always applied. If set to "visible" this class is never applied. If set to "auto" this class is only applied if a overflow on the y-axis is present.)
* | The class name(s) which is set by the option "className".

Scrollbars
Now that we are aware of the class names of the host-element, we can continue with the structure of the scrollbars.
Both scrollbars have the same DOM structure.
Here is a draft of the scrollbars DOM structure as well as the intended design:
Hover over the DOM or Design elements to get visual feedback.

    <div class="os-host">
        <!-- ... --->
        <div class="os-scrollbar os-scrollbar-horizontal">
            <div class="os-scrollbar-track">
                <div class="os-scrollbar-handle">
                </div>
            </div>
        </div>
        <div class="os-scrollbar os-scrollbar-vertical">
            <div class="os-scrollbar-track">
                <div class="os-scrollbar-handle">
                </div>
            </div>
        </div>
        <div class="os-scrollbar-corner">
        </div>
    </div>

scrollable-content
Each of the scrollbar elements can have additional classes. These classes get added if a certain behavior is fulfilled.
Here is a complete listing of all class names of the .os-scrollbar element:

Class Name | Description
.os-scrollbar | Indicates that this element is a scrollbar. (The root element of all scrollbar elements)
.os-scrollbar-horizontal | Indicates that this element is a horizontal scrollbar.
.os-scrollbar-vertical | Indicates that this element is a vertical scrollbar.
.os-scrollbar-auto-hidden | Indicates that this scrollbar is hidden because of the "autoHide" option. Note that this scrollbar is potentially visible and is only hidden due to the configurated "autoHide" effect.
.os-scrollbar-auto-hidden | Indicates that this scrollbar is hidden because of the "autoHide" option. Note that this scrollbar is potentially visible and is only hidden due to the configurated "autoHide" effect.
.os-scrollbar-unusable | Indicates that this scrollbar is not usable due to no overflow or deactivation via the "overflowBehavior" option.

Here is a complete listing of all class names of the os-scrollbar-track element:

Class Name | Description
.os-scrollbar-track | Indicates that this element is a scrollbar track.
.os-scrollbar-track-off | Indicates that click scrolling is not possible. Only applied if the "scrollbars.clickScrolling" option is false.

Here is a complete listing of all class names of the .os-scrollbar-handle element:

Class Name | Description
.os-scrollbar-handle | Indicates that this element is a scrollbar handle.
.os-scrollbar-handle-off | Indicates that drag scrolling is not possible. Only applied if the "scrollbars.dragScrolling" option is false.

Styling
Basics
Please read first the Class Names section before you do any styling. It's very important to understand the class names and their meaning to not mess anything up!
Do only change styles of element which have the following class names:

Element
.os-scrollbar
.os-scrollbar-track
.os-scrollbar-handle
.os-scrollbar-corner

Don't change the values of the CSS properties `opacity`, `transition` and `visibility` on the `.os-scrollbar` elements! They are handled automatically.
Please also don't apply `padding` or `border` to the `.os-scrollbar-track` elements.
If you have to apply a style to any other element which is generated by the plugin, it's most likely wrong and there must be a different way. If this isn't the case, please open a issue on github.
Due to necessary Javascript optimization the ":active" pseudo-class doesn't work / won't be applied on all elements listed above. A class with the name ".active" will be applied instead to provide the same functionality. Here is a example how you must write your selector if you want to style an ":active" element:

    /* incorrect */
    .os-scrollbar:active,
    .os-scrollbar-track:active,
    .os-scrollbar-handle:active {
        /* DON'T use the :active pseudo-class */
    }

    /* correct */
    .os-scrollbar.active,
    .os-scrollbar-track.active,
    .os-scrollbar-handle.active {
        /* USE the .active class insted */
    }

Theme inheritance
Let's say you like the built-in "dark" theme, but you hate the rounded corners of the handles.
Well, in this case you don't have to rewrite the whole style again.
You can add multiple classes via the "className" option. Just separate them with blanks (spaces).
Now you can do something like that:

    //initialize the plugin with custom classnames
    OverlayScrollbars(document.getElementById(id), {
        className : "os-theme-dark os-theme-dark-edgy"
    });

After this command, your host-element has the "dark" -theme applied but has also the class `.os-theme-dark-edgy`.
Now you can define some additional style rules:

    .os-theme-dark.os-theme-dark-edgy > .os-scrollbar > .os-scrollbar-track > .os-scrollbar-handle {
        border-radius: 0px;
    }

Make sure that this rule overrules the default "dark" -theme rules (e.g. put it at the bottom or use `!important`).
That's it! With this "system" you can achieve very flexible styling.
Scrollbar handle length
You can change the scrollbar-handle length via CSS. I know, it's a bit unusual to do it that way, but it's the most efficient and elegant way, since you can do anything with any CSS-unit such as pixel, percent and so on.
Below is a full example how to achieve different handle-length styles across different instances.
First we write our CSS style rules, note the selector, this styles only apply if the host-element has the class `limited-handles`:
If you want fixed size handles, set the min- and max- length of the handle to the same value.

    .limited-handles > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle {
        max-width: 50%;
        min-width: 30px;
    }
    .limited-handles > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle {
        max-height: 50%;
        min-height: 30px;
    }

We have defined the required CSS, now we have to initialize the plugin correctly with the above described theme inheritance technique:

    OverlayScrollbars(document.getElementById(id), {
        className : "os-theme-dark limited-handles"
    });

The result looks like this:
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.
Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae.
Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Scrollbar position and length
This is pretty much the same as changing the handle-length.
First we write our CSS style rules:

    .deviant-scrollbars > .os-scrollbar-horizontal {
        top: 0;
        right: 0;
        bottom: auto;
        left: 10px;
        width: 50%;
        background: rgba(0, 0, 255, 0.3);
    }
    .deviant-scrollbars > .os-scrollbar-vertical {
        left: 0;
        bottom: 0;
        right: auto;
        top: 10px;
        height: 50%;
        background: rgba(255, 0, 0, 0.3);
    }
    .deviant-scrollbars.os-host-scrollbar-horizontal-hidden > .os-scrollbar-vertical {
        top: 0;
    }
    .deviant-scrollbars.os-host-scrollbar-vertical-hidden > .os-scrollbar-horizontal {
        left: 0;
    }

Then we initialize the plugin correctly:

    OverlayScrollbars(document.getElementById(id), {
        className : "os-theme-dark deviant-scrollbars"
    });

The result looks like this:
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non.
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo?
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti.
Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere.
Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui rationeunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt.
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum?
Template(s)
In the themes section you can find CSS templates for the most common scrollbar styles.
You can download and customize them as you want.
Here is a simple but very efficient SCSS template. (even if you dont know SCSS, this template will give you a basic idea)
If you don't need anything too fancy this template should be well suited for your needs.
Just copy & paste it and set the variables as you like:

    //your theme name
    $theme-name: os-theme-custom;

    //horizontal scrollbar
    $scrollbar-horizontal-size: 6px; //horizontal scrollbar height
    $scrollbar-horizontal-padding: 2px;
    $scrollbar-horizontal-inner-expansion: 6px;
    $scrollbar-horizontal-track-background: transparent;
    $scrollbar-horizontal-track-background-hover: transparent;
    $scrollbar-horizontal-track-background-active: transparent;
    $scrollbar-horizontal-track-transition: background-color 0.3s;
    $scrollbar-horizontal-handle-min-size: 30px; //horizontal scrollbar handle min width
    $scrollbar-horizontal-handle-max-size: none; //horizontal scrollbar handle max width
    $scrollbar-horizontal-handle-background: rgba(0, 0, 0, 0.4);
    $scrollbar-horizontal-handle-background-hover: rgba(0, 0, 0, 0.6);
    $scrollbar-horizontal-handle-background-active: rgba(0, 0, 0, 1);
    $scrollbar-horizontal-handle-transition: background-color 0.3s;

    //vertical scrollbar
    $scrollbar-vertical-size: 6px; //vertical scrollbar width
    $scrollbar-vertical-padding: 2px;
    $scrollbar-vertical-inner-expansion: 6px;
    $scrollbar-vertical-track-background: transparent;
    $scrollbar-vertical-track-background-hover: transparent;
    $scrollbar-vertical-track-background-active: transparent;
    $scrollbar-vertical-track-transition: background-color 0.3s;
    $scrollbar-vertical-handle-min-size: 30px; //vertical scrollbar handle min height
    $scrollbar-vertical-handle-max-size: none; //vertical scrollbar handle max height
    $scrollbar-vertical-handle-background: rgba(0, 0, 0, 0.4);
    $scrollbar-vertical-handle-background-hover: rgba(0, 0, 0, 0.6);
    $scrollbar-vertical-handle-background-active: rgba(0, 0, 0, 1);
    $scrollbar-vertical-handle-transition: background-color 0.3s;

    //scrollbar corner
    $scrollbar-corner-background-color: transparent;

    .#{$theme-name} > .os-scrollbar-horizontal {
        right: $scrollbar-vertical-size + ($scrollbar-vertical-padding * 2);
        height: $scrollbar-horizontal-size;
        padding: $scrollbar-horizontal-padding;
    }
    .#{$theme-name} > .os-scrollbar-vertical {
        bottom: $scrollbar-horizontal-size + ($scrollbar-horizontal-padding * 2);
        width: $scrollbar-vertical-size;
        padding: $scrollbar-vertical-padding;
    }
    .#{$theme-name}.os-host-rtl > .os-scrollbar-horizontal {
        left: $scrollbar-vertical-size + ($scrollbar-vertical-padding * 2);
        right: 0;
    }
    .#{$theme-name} > .os-scrollbar-corner {
        height: $scrollbar-horizontal-size + ($scrollbar-horizontal-padding * 2);
        width: $scrollbar-vertical-size + ($scrollbar-vertical-padding * 2);
        background-color: $scrollbar-corner-background-color;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track {
        background: $scrollbar-horizontal-track-background;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track {
        background: $scrollbar-vertical-track-background;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track:hover {
        background: $scrollbar-horizontal-track-background-hover;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track:hover {
        background: $scrollbar-vertical-track-background-hover;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track.active {
        background: $scrollbar-horizontal-track-background-active;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track.active {
        background: $scrollbar-vertical-track-background-active;
    }
    .#{$theme-name}.os-host-transition > .os-scrollbar-horizontal > .os-scrollbar-track {
        -webkit-transition: $scrollbar-horizontal-track-transition;
                transition: $scrollbar-horizontal-track-transition;
    }
    .#{$theme-name}.os-host-transition > .os-scrollbar-vertical > .os-scrollbar-track {
        -webkit-transition: $scrollbar-vertical-track-transition;
                transition: $scrollbar-vertical-track-transition;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle:before,
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle:before {
        content: '';
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        display: block;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle:before {
        top: -$scrollbar-horizontal-inner-expansion;
        bottom: -$scrollbar-horizontal-padding;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle:before {
        left: -$scrollbar-vertical-inner-expansion;
        right: -$scrollbar-vertical-padding;
    }
    .#{$theme-name}.os-host-rtl > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle:before {
        right: -$scrollbar-vertical-inner-expansion;
        left: -$scrollbar-vertical-padding;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle {
        border-radius: $scrollbar-horizontal-size;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle {
        border-radius: $scrollbar-vertical-size;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle {
        min-width: $scrollbar-horizontal-handle-min-size;
        max-width: $scrollbar-horizontal-handle-max-size;
        background: $scrollbar-horizontal-handle-background;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle {
        min-height: $scrollbar-vertical-handle-min-size;
        max-height: $scrollbar-vertical-handle-max-size;
        background: $scrollbar-vertical-handle-background;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle:hover {
        background: $scrollbar-horizontal-handle-background-hover;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle:hover {
        background: $scrollbar-vertical-handle-background-hover;
    }
    .#{$theme-name} > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle.active {
        background: $scrollbar-horizontal-handle-background-active;
    }
    .#{$theme-name} > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle.active {
        background: $scrollbar-vertical-handle-background-active;
    }
    .#{$theme-name}.os-host-transition > .os-scrollbar-horizontal > .os-scrollbar-track > .os-scrollbar-handle {
        -webkit-transition: $scrollbar-horizontal-handle-transition;
                transition: $scrollbar-horizontal-handle-transition;
    }
    .#{$theme-name}.os-host-transition > .os-scrollbar-vertical > .os-scrollbar-track > .os-scrollbar-handle {
        -webkit-transition: $scrollbar-vertical-handle-transition;
                transition: $scrollbar-vertical-handle-transition;
    }

If you have any problems with styling or you can't achieve your desired style, open a issue on github.
DOM Elements
To achieve the desired functionality, the plugin adds additional elements to your DOM.
Each element has a specific purpose.
DOM Before plugin initialization:
Textarea Element

.............

..........................................

..................................................

..........................................................................................

............................

................................

........................................................................

..........................................

.....................

..................................................................

............................

.............................................................................

.....................................

..................................................

..........................................................................................

............................

................................

........................................................................

Host Element
Content Item 1
Content Item 2
Content Item 3
DOM After plugin initialization:
Host Element
Size Observer Element
Size Auto Observer Element
Content Glue Element
Padding Element
Viewport Element
Content Arrange Element
Content Element
Textarea Element

.............

..........................................

.....................

Content Item 1
Content Item 2
Content Item 3
Scrollbar Horizontal Element
Scrollbar Vertical Element
Scrollbar Corner Element

Textarea:

The element to which the plugin was initialized (target element).
After initialization this element gets wrapped by other divs and is affected by scrolling.
To guarantee the proper functionality this element's style is heavily affected by the plugin.

Host Element:

After initialization it is the root element which contains all divs of the plugin.

Host Element:

The element to which the plugin was initialized (target element).
After initialization it is the root element which contains all divs of the plugin.
This element is not affected by any inline styles.

Content Item Element(s):

The element(s) which are affected by scrolling.
If the target element is a textarea, the textarea is this element.

Size Observer Element:

Detects any size, padding, border, margin and direction changes of the host element.
This element is applied even if the ResizeObserver API is supported, because of the padding and direction change detection.

Size Auto Observer Element:

Only applied if the plugin is initialized with the option `sizeAutoCapable: true` or if the option is set for the first time to true.
Detects if the host element has auto height, auto width or both.

Content Glue Element:

Only applied if the plugin is initialized with the option `sizeAutoCapable: true` or if the option is set for the first time to true.
Is responsible for the correct sizing of auto sized elements.

Padding Element:

Manages the correct padding appearance. The size of this elements is the correct viewport size, since this element never has margin, padding or border values applied.

Viewport Element:

The element which contains the native scrollbars and thus is responsible for the scrolling itself. In order to hide the native scrollbars this element can have margin, padding, border as well as absolute position values applied.

Content Arrange Element:

Only applied if scrollbars are natively overlaid and the browser isn't capable of native Scrollbar-Styling. Is responsible for the correct hiding of natively overlaid scrollbars and the correct scroll position. If the target-element is the body element, this element is also responsible for the correct min-width and min-height if specified.

Content Element:

Is responsible for the correct appearance of percent sized elements as well as for measuring the correct overflow values.

Scrollbar Horizontal / Vertical Element:

These elements are the custom styled scrollbar elements. The inner structure of each scrollbar element looks like:
Scrollbar Element
Scrollbar Track Element
Scrollbar Handle Element

Scrollbar Track Element:

Responsible for scrolling with a mouse down on the track.

Scrollbar Handle Element:

Responsible for drag scrolling and scroll position indication.

Scrollbar Corner Element:

This element is responsible for resizing (if activated) or for style purposes only.
Compatibility
A object which offers compatibility methods. These methods are unifying native methods which are different or not present across all browsers. (for example if methods or objects have vendor prefixes, different names or signatures and so on...)

###### Structure:

    {
        wW   : function,
        wH   : function,
        mO   : function,
        rO   : function,
        rAF  : function,
        cAF  : function,
        now  : function,
        stpP : function ( event ),
        prvD : function ( event ),
        page : function ( event ),
        mBtn : function ( event ),
        inA  : function ( item, array ),
        isA  : function ( array ),
        type : function ( obj ),
        bind : function ( function, thisObj [, arg1[, arg2[, ...]]] )
    }

###### Description:

wW
A function without parameters which returns the window width.

    //Example usage
    var wndWidth = compatibility.wW();

wH
A function without parameters which returns the window height.

    //Example usage
    var wndHeight = compatibility.wH();

mO
A function without parameters which returns a MutationObserver object or undefined if the browser doesn't support it.

    //Example usage
    var mO = compatibility.mO();
    if(mO) {
        var myMutationObserver = new mO(function(mutations) {
            console.log(mutations);
        });
    }

rO
A function without parameters which returns a ResizeObserver object or undefined if the browser doesn't support it.

    //Example usage
    var rO = compatibility.rO();
    if(rO) {
        var myResizeObserver = new rO(function(entries) {
            console.log(entries);
        });
    }

rAF
A function without parameters which returns the requestAnimationFrame function or a corresponding polyfill function if the browser doesn't support it.

    //Example usage
    var rAF = compatibility.rAF();
    var requestID = rAF(function() { /* example code */ });

cAF
A function without parameters which returns the cancelAnimationFrame function or a corresponding polyfill function if the browser doesn't support it.

    //Example usage
    var rAF = compatibility.rAF();
    var requestID = rAF(function() { /* example code */ });
    var cAF = compatibility.cAF();
    cAF(requestID);

now
A function without parameters which returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
Like Date.now() but it also works in IE8 or older browsers.

    //Example usage
    var time = compatibility.now();

stpP
A function with one parameter which prevents further propagation of the given event in the capturing and bubbling phases.
Like Event.stopPropagation() but it also works in IE8 or older browsers.

    //Example usage
    document.addEventListener('mousedown', function(event) {
        compatibility.stpP(event);
    });

prvD
A function with one parameter which prevents the default action of the given event.
Like Event.preventDefault() but it also works in IE8 or older browsers.

    //Example usage
    document.addEventListener('mousedown', function(event) {
        compatibility.prvD(event);
    });

page
Gets the pageX and pageY values of the given mouse event.
Works also in IE8 or older browsers.

    //Example usage
    document.addEventListener('mousedown', function(event) {
        var page = compatibility.page(event);
        var pageX = page.x;
        var pageY = page.y;
    });

mBtn
Gets the clicked mouse button of the given mouse event. Returns 1 for left button, 2 for middle and 3 for right.
Works also in IE8 or older browsers.

    //Example usage
    document.addEventListener('mousedown', function(event) {
        var mouseButton = compatibility.mBtn(event);
    });

inA
A function with two parameters which returns the index of the given item in the given array or -1 if the item isn't in the given array.
This function should be only used if you need the index of a specific DOM-Element in a array of DOM-Elements, because it prevents the SCRIPT70 Permission denied error to happen, but due to that it can be slower.

    //Example usage
    var array = document.querySelectorAll('*');
    var index = compatibility.inA(document.body, array);

isA
A function with one parameter which returns a boolean which indicates whether the given argument is an array.

    //Example usage
    var first = [ 1, 2, 3 ];
    var second = { prop : "value" };
    framework.isArray(first);  //true
    framework.isArray(second); //false

type
A function with one parameter which returns the internal JavaScript [[Class]] of an object.
This function is the equivalent to the jQuery type function, but because jQuery is deprecating it, it's in this compatibility object.

    //Example usage
    //following statements are true:
    framework.type(undefined)          === "undefined";
    framework.type()                   === "undefined";
    framework.type(window.notDefined)  === "undefined";
    framework.type(null)               === "null";
    framework.type(true)               === "boolean";
    framework.type(new Boolean())      === "boolean";
    framework.type(3)                  === "number";
    framework.type(new Number(3))      === "number";
    framework.type("test")             === "string";
    framework.type(new String("test")) === "string";
    framework.type(function() { })     === "function";
    framework.type([ ])                === "array";
    framework.type(new Array())        === "array";
    framework.type(new Date())         === "date";
    framework.type(new Error())        === "error";
    framework.type(/test/)             === "regexp";

bind
Creates a new function that, when called, has its 'this' keyword set to the given thisObj value, with a given sequence of arguments preceding any provided when the new function is called.
Like Function.prototype.bind() but it also works in IE8 or older browsers.

    //Example usage
    var add = function(a, b) { return this + a + b; }
    var add012 = compatibility.bind(add, 0, 1, 2);
    var result = add012(); //3

Framework
The framework which OverlayScrollbars is using internally in order to make it simpler to manipulate and traverse the DOM. If the jQuery version is used, this parameter is the jQuery object. However, if the non-jQuery version is used, this parameter is a jQuery-like-object which has the same API-structure as jQuery but doesn't offer all its functionality.
Below is a list which methods are definitely supported:

###### Utilities:

.extend ( [deep], target [, object1 ] [, objectN ] )
Merge the contents of two or more objects together into the first object.
read the jQuery Documentation

    //Example usage
    var clone = framework.extend({ }, object1, object2);
    var deepClone = framework.extend(true, { }, object1, object2);

.isEmptyObject ( object )
Determine whether an object is empty (contains no enumerable properties).
read the jQuery Documentation

    //Example usage
    framework.isEmptyObject({ });               // true
    framework.isEmptyObject({ prop: "value" }); // false

.isPlainObject ( object )
Determine whether an object is a plain object (created using "{ }" or "new Object")
read the jQuery Documentation

    //Example usage
    framework.isPlainObject({ });    // true
    framework.isPlainObject("test"); // false

.each ( array, callback )
A generic iterator function, which can be used to seamlessly iterate over both objects and arrays.
read the jQuery Documentation

    //Example usage
    var array = [ 10, 20, 30 ];
    framework.each(array, function(index, value) {
        console.log(value);
    });

.inArray ( value, array [, fromIndex ] )
Search for a specified value within an array and return its index (or -1 if not found).
read the jQuery Documentation

    //Example usage
    var array = [ 10, 20, 30, 40 ];
    framework.inArray(40, array); //4

###### DOM Node inserting / removing:

.append ( content )
Inserts content, specified by the content parameter, to the end of each element in the set of matched elements.
Differences to jQuery:

- The method doesn't accept any optional parameters.
- The "content" parameter can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div").append("<div></div>");

    var myElm = framework("<div></div>");
    framework("div").append(myElm);

.prepend ( content )
Inserts content, specified by the parameter, to the beginning of each element in the set of matched elements.
Differences to jQuery:

- The method doesn't accept any optional parameters.
- The "content" parameter can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div").prepend("<div></div>");

    var myElm = framework("<div></div>");
    framework("div").prepend(myElm);

.before ( content )
Inserts content, specified by the parameter, before each element in the set of matched elements.
Differences to jQuery:

- The method doesn't accept any optional parameters.
- The "content" parameter can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div").before("<div></div>");

    var myElm = framework("<div></div>");
    framework("div").before(myElm);

.after ( content )
Inserts content, specified by the parameter, after each element in the set of matched elements.
Differences to jQuery:

- The method doesn't accept any optional parameters.
- The "content" parameter can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div").after("<div></div>");

    var myElm = framework("<div></div>");
    framework("div").after(myElm);

.remove ( )
Remove the set of matched elements from the DOM.
Differences to jQuery:

- The method doesn't accept any optional parameters.

read the jQuery Documentation

    //Example usage
    framework("div").remove();

.wrap ( wrappingHtml )
Wrap an HTML structure around each element in the set of matched elements.
Differences to jQuery:

- The parameter "wrappingHtml" can only be a string.

read the jQuery Documentation

    //Example usage
    framework("div").wrap("<div></div>");

.wrapAll ( wrappingHtml )
Wrap an HTML structure around all elements in the set of matched elements.
Differences to jQuery:

- The parameter "wrappingHtml" can only be a string.

read the jQuery Documentation

    //Example usage
    framework("div").wrapAll("<div></div>");

.wrapInner ( wrappingHtml )
Wrap an HTML structure around the content of each element in the set of matched elements.
Differences to jQuery:

- The parameter "wrappingHtml" can only be a string.

read the jQuery Documentation

    //Example usage
    framework("div").wrapInner("<div></div>");

.unwrap ( )
Remove the parents of the set of matched elements from the DOM, leaving the matched elements in their place.
Differences to jQuery:

- The method doesn't accept any optional parameters.

read the jQuery Documentation

    //Example usage
    framework("div").unwrap();

###### DOM Node manipulation / information:

.css ( propertyName [, value] )
Get one or set one or more CSS properties for the set of matched elements.
The .css( properties ) signature is also supported. Differences to jQuery:

- The "propertyName" parameter always has to be a string and can't be anything other.
- The "value" parameter always has to be a string and can't be anything other.

read the jQuery Documentation

    //Example usage
    framework("div").css("display"); //get the current css "display" of the matched element
    framework("div").css("display", "none"); //set the css display value to "none"
    framework("div").css({ opacity: 1, display: "block", background: "red" }); //change multiple styles

.hasClass ( className )
Determine whether any of the matched elements are assigned the given class.
read the jQuery Documentation

    //Example usage
    framework("div.test-class").hasClass("test-class"); //true

.addClass ( className )
Adds the specified class(es) to each element in the set of matched elements.
Differences to jQuery:

- The "className" parameter has always to be a string and can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div.test-class-one").addClass("test-class-two"); //add one class
    framework("div.test-class-one").addClass("test-class-two test-class-three"); //add mutliple classes

.removeClass ( className )
Removes the specified class(es) from each element in the set of matched elements.
Differences to jQuery:

- The "className" parameter has always to be a string and can't be a function or empty.

read the jQuery Documentation

    //Example usage
    framework("div.test-class-one").removeClass("test-class-two"); //removes one class
    framework("div.test-class-one").removeClass("test-class-two test-class-three"); //removes mutliple classes

.offset ( )
Get the current coordinates of the first element in the set of matched elements, relative to the document.
Differences to jQuery:

- The methods desn't accept any parameters. You can't set the offset, you can only get it.

read the jQuery Documentation

    //Example usage
    framework("div").offset(); //gets the offset of the first found div element

.position ( )
Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
read the jQuery Documentation

    //Example usage
    framework("div").position(); //gets the position of the first found div

.scrollLeft ( [value] )
Gets or sets the scrollLeft offset of the matched elements.
read the jQuery Documentation

    //Example usage
    framework("div").scrollLeft(); //gets the scrollLeft offset of the first found div
    framework("div").scrollLeft(200); //sets the scrollLeft offset to 200 for all found divs

.scrollTop ( [value] )
Gets or sets the scrollTop offset of the matched elements.
read the jQuery Documentation

    //Example usage
    framework("div").scrollTop(); //gets the scrollTop offset of the first found div
    framework("div").scrollTop(200); //sets the scrollTop offset to 200 for all found divs

.val ( [value] )
.attr ( attributeName [, value] )
Gets or sets the value of an attribute for the set of matched elements.
Differences to jQuery:

- The "attributeName" parameter has always to be a string and cant be a object.
- The "value" parameter can't be a function.

read the jQuery Documentation

    //Example usage
    framework("div").attr("id"); //get the attribute "id" of the first matched element
    framework("div").attr("id", "myId"); //set the attribute "id" for the matched element(s)

.removeAttr ( attributeName )
Remove an attribute from each element in the set of matched elements.
read the jQuery Documentation

    //Example usage
    framework("div").removeAttr("id"); //remove the attribute "id" for the matched elements

Gets or sets the current value of the matched elements.
read the jQuery Documentation

    //Example usage
    framework("input").val(); //gets the value of the first found input element
    framework("input").val("hello world"); //sets the value for all found input elements to "hello world"

.hide ( )
Hide the matched elements.
Differences to jQuery:

- The method doesn't accept any additional parameters such as "duration", "complete" or "options".

read the jQuery Documentation

    //Example usage
    framework("div").hide();

.show ( )
Shows the matched elements.
Differences to jQuery:

- Sets the css "display" value always to "block" (ignores the the default display value).
- The method doesn't accept any additional parameters such as "duration", "complete" or "options".

read the jQuery Documentation

    //Example usage
    framework("div").show();

###### DOM traversal / filtering:

.first ( )
Reduce the set of matched elements to the first in the set.
read the jQuery Documentation

    //Example usage
    framework("div").first(); //reduced to the first found div element

.last ( )
Reduce the set of matched elements to the final one in the set.
read the jQuery Documentation

    //Example usage
    framework("div").last(); //reduced to the last found div element

.eq ( index )
Reduce the set of matched elements to the one at the specified index.
Providing a negative number as index indicates a position starting from the end of the set, rather than the beginning read the jQuery Documentation

    //Example usage
    framework("div").eq(2); //reduced to the 2nd div which was found
    framework("div").eq(-2); //reduced to the 2nd last div which was found

.find ( selector )
Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
Differences to jQuery:

- The "selector" parameter has to be a string and can't be DOM-Element.
- The provided selector has to be supported by Document.querySelectorAll. (:not() and so on aren't supported)

read the jQuery Documentation

    //Example usage
    framework("ul").find("li:first-child"); //returns the first list element

.children ( [selector] )
Get the children of each element in the set of matched elements, optionally filtered by a selector.
Differences to jQuery:

- The provided selector has to be supported by Document.querySelectorAll. (:not() and so on aren't supported)

read the jQuery Documentation

    //Example usage
    framework("ul").children(); //returns all list elements of the list

.parent ( [selector] )
Get the parent of each element in the current set of matched elements, optionally filtered by a selector.
Differences to jQuery:

- The provided selector has to be supported by Document.querySelectorAll. (:not() and so on aren't supported)

read the jQuery Documentation

    //Example usage
    framework("li").parent(); //returns the "ul" element of the list element

.is ( selector )
Check the current matched set of elements against a selector.
Also supports the pseudo-selectors `:hidden` and `:visible` - Read more
Differences to jQuery:

- The "selector" parameter has to be a string and can't be a function or anything other.
- The provided selector has to be supported by Document.querySelectorAll. (:not() and so on aren't supported)

read the jQuery Documentation

    //Example usage
    framework("div").is("body"); //false
    framework("div").is(":hidden");
    framework("div").is(":visible");

.contents ( )
Get the children of each element in the set of matched elements, including text and comment nodes.
read the jQuery Documentation

    //Example usage
    framework("div").contents();

.each ( function )
Iterate over all selected elements executing a function for each matched element.
read the jQuery Documentation

    //Example usage
    framework("div").each(function(index, element) {
        console.log(index);
        console.log(element);
    });

###### Events:

.on ( events, handler )
Adds the given event handler function for one or more events to the selected elements.
Differences to jQuery:

- The method doesn't accept the optional parameters "selector" and "data".
- The "event" parameter has to be a string and can't be a object.

read the jQuery Documentation

    var exampleCallback = function(event) { console.log(event); };
    //Example usage with a single event
    framework("button").on("click", exampleCallback);
    //Example usage with multiple events
    framework("body").on("mousedown mouseup mousemove", exampleCallback);

.off ( events, handler )
Removes the given event handler function for one or more events from the selected elements.
Differences to jQuery:

- The method doesn't accept the optional parameter "selector".
- The "event" parameter has to be a string and can't be a object.
- The function can't be called without parameters.

read the jQuery Documentation

    var exampleCallback = function(event) { console.log(event); };
    //Example usage with a single event
    framework("button").off("click", exampleCallback);
    //Example usage with multiple events
    framework("body").off("mousedown mouseup mousemove", exampleCallback);

.one ( events, handler )
Adds the given event handler function for one or more events to the selected elements. The event handler function gets removed automatically after its first execution.
Differences to jQuery:

- The method doesn't accept the optional parameter "selector" and "data".
- The "event" parameter has to be a string and can't be a object.

read the jQuery Documentation

    var exampleCallback = function(event) { console.log(event); };
    //Example usage with a single event
    framework("button").one("click", exampleCallback);
    //Example usage with multiple events
    framework("body").one("click keydown", exampleCallback);

.trigger ( event )
Execute all handlers and behaviors attached to the matched elements for the given event.
Differences to jQuery:

- The method doesn't accept the optional parameter "extraParameters".

read the jQuery Documentation

    //Example usage
    framework("button").on("click", function(event) { console.log(event); });
    framework("button").trigger("click");

###### Animation:

.animate ( properties [, duration ] [, easing ] [, complete ] )
Performs a custom animation of a set of CSS properties. You can also animate "scrollLeft" and "scrollTop".
The .animate( properties, options ) signature is supported.
Differences to jQuery:

- Promises such as "always", "fail", "done" and "start" aren't supported.
- You can't choose a optional queue for your animation.
- You can only animate in "px" or float (such as "opacity: 0.5"). Units like "%" or "em" aren't supported.
- Relative animations with "+=" or "-=" aren't supported.
- The duration parameter has always to be a number and can't be a string.
- The only supported callback functions are: "step", "progress" and "complete".

read the jQuery Documentation

    //Example usage
    framework("div").animate({ height: "50px", opacity: 0.5, scrollTop : 0 }, 1000);

.stop ( [clearQueue ] [, jumpToEnd ] )
Stops the currently-running animations on the matched elements.
Differences to jQuery:

- The optional "queue" parameter isn't supported since you can't choose custom queues for your animations.

read the jQuery Documentation

    //Example usage
    framework("div").animate({ height: "50px", opacity: 0.5, scrollTop : 0 }, 1000);
    framework("div").stop(); //the animation above is stopped immediately