7.3.2 • Published 2 years ago

@chapiter/smooth-scrollbar v7.3.2

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Smooth Scrollbar

npm npm npm Travis

Smooth scrolling in modern browsers.

Table of Contents

Install

Via npm:

npm install smooth-scrollbar --save

Via bower:

bower install smooth-scrollbar --save

Browser Compatibility

BrowserVersion
IE10+
Chrome22+
Firefox16+
Safari8+
Android Browser4+
Chrome for Android32+
iOS Safari7+

Demo

http://idiotwu.github.io/smooth-scrollbar/

Why is native scrolling slow?

As is explained in this article, browser repaint every frame in scrolling. Less painting is better.

To avoid repainting, I use translate3d in scroll content to create composite layers and force hardware accelerating.

Usage

Smooth scrollbar is defined as an UMD module which named Scrollbar, you can use any loader to load it:

import Scrollbar from 'smooth-scrollbar';

Or get it from window object:

var Scrollbar = window.Scrollbar;

Don't forget to include the stylesheet in your page:

<link rel="stylesheet" href="dist/smooth-scrollbar.css">

There are three ways to tell the plugin which element should be a smooth scrollbar:

  1. As an element:

    <scrollbar>...</scrollbar>
  2. As an attribute:

    <section scrollbar>...</section>
  3. As a data attribute

    <section data-scrollbar>...</section>

Then init all scrollbars:

Scrollbar.initAll(options);

Or you can call Scrollbar.init(elem, options) to manually init the scrollbar:

Scrollbar.init(document.getElementById('my-scrollbar'), options);

Available Options for Scrollbar

parametertypedefaultdescription
speedNumber1Scrolling speed scale.
dampingNumber0.1Delta reduction damping, a float value between (0, 1), the lower the value is, the more smooth the scrolling will be.
thumbMinSizeNumber20Minimal size for scrollbar thumb.
syncCallbacksBooleanfalseExecute listeners in synchronous or asynchronous.
renderByPixelsBooleantrueRender scrolling by integer pixels, set to true to improve performance.
alwaysShowTracksBooleanfalseKeep scrollbar tracks visible whether it's scrolling or not.
continuousScrollingBoolean|String'auto'Whether allow upper scrollable content to continue scrolling when current scrollbar reaches edge. When set to 'auto', it will be enabled on nested scrollbars, and disabled on first-class scrollbars.
overscrollEffectBoolean|StringfalseExperimental overscroll effect, 'bounce' for iOS style effect and 'glow' for Android style effect. Be careful when you enable this feature!
overscrollEffectColorString'#87ceeb'Canvas paint color with 'glow' effect.
overscrollDampingNumber0.2The same as damping, but for overscrolling.

Confusing with the option field? Try edit tool here!

DOM Structure

Following is the DOM structure that Scrollbar yields:

<scrollbar>
    <article class="scroll-content">
        your contents here...
    </article>
    <aside class="scrollbar-track scrollbar-track-x">
        <div class="scrollbar-thumb scrollbar-thumb-x"></div>
    </aside>
    <aside class="scrollbar-track scrollbar-track-y">
        <div class="scrollbar-thumb scrollbar-thumb-y"></div>
    </aside>
</scrollbar>

APIs

In this documentation, we are using Scrollbar (in capitalized) to represent the constructor and scrollbar (in lowercase) for the instance object.

Static Methods

Scrollbar.init()

Scrollbar.init(elem, options?): SmoothScrollbar
ParamTypeDescription
elemElementThe DOM element that you want to initialize scrollbar to.
optionsobject, optionalInitial options, see Available Options for Scrollbar section above.

Initializes a scrollbar on the given element and returns scrollbar instance:

var scrollbar = Scrollbar.init(document.body, { speed: 0.75 });

Scrollbar.initAll()

Scrollbar.init(options): [SmoothScrollbar]
ParamTypeDescription
optionsobject, optionalInitial options, see Available Options for Scrollbar section above.

Automatically init scrollbar on all elements refer to the selector scrollbar, [scrollbar], [data-scrollbar], returns an array of scrollbars collection:

<scrollbar> ... </scrollbar>

<article scrollbar> ... </article>

<article data-scrollbar> ... </article>
Scrollbar.initAll(); // [ SmoothScrollbar, SmoothScrollbar, SmoothScrollbar ]

Scrollbar.has()

Scrollbar.has(elem): boolean
ParamTypeDescription
elemElementThe DOM element that you want to check.

Check if scrollbar exists on given element:

Scrollbar.init(document.body);

Scrollbar.has(document.body); // true

Scrollbar.get()

Scrollbar.get(elem): SmoothScrollbar
ParamTypeDescription
elemElementThe DOM element that you want to check.

Get scrollbar on the given element, if no scrollbar instance exsits, return undefined:

var scrollbar = Scrollbar.init(document.body);

Scrollbar.get(document.body) === scrollbar; // true

Scrollbar.get(document.documentElement); // undefined

Scrollbar.getAll()

Scrollbar.getAll(): [SmoothScrollbar]

Return an array that contains all scrollbar instances:

Scrollbar.getAll(); // [ SmoothScrollbar, SmoothScrollbar, ... ]

Scrollbar.destroy()

Scrollbar.destroy(elem): void
ParamTypeDescription
elemElementThe DOM element that scrollbar is initialized to.

Remove scrollbar on the given element.

Scrollbar.destroyAll()

Scrollbar.destroyAll(): void

Remove all scrollbar instances from current page.

Instance Properties and Methods

A scrollbar instance refer to what you get from Scrollbar.init() method:

var scrollbar = Scrollbar.init(elem)

scrollbar.targets

  • Type: object

An object that contains main parts of current scrollbar:

{
    container,
    content,
    xAxis: { track, thumb },
    yAxis: { track, thumb }
}

scrollbar.offset

  • Type: object

Current scrolling offset:

console.log(scrollbar.offset); // { x: 123, y: 456 }

scrollbar.limit

  • Type: object

Max-allowed scrolling distance:

console.log(scrollbar.limit); // { x: 1000, y: 1000 }

scrollbar.scrollTop

  • Type: number

Alias for scrollbar.offset.y:

console.log(scrollbar.scrollTop); // 123

console.log(scrollbar.scrollTop === scrollbar.offset.y); // true

scrollbar.scrollLeft

  • Type: number

Alias for scrollbar.offset.x:

console.log(scrollbar.scrollLeft); // 456

console.log(scrollbar.scrollLeft === scrollbar.offset.x); // true

scrollbar.wheelReversed

  • Type: boolean

Whether event wheel is reversed:

console.log(scrollbar.wheelReversed); // true or false

scrollbar.reverseWheel()

scrollbar.reverseWheel(reverse): void
ParamTypeDescription
reversebooleantrue for reverse axis.

Invert the axis of the wheel event.

scrollbar.reverseWheel(true);
console.log(scrollbar.reverseWheel); // true

scrollbar.update()

scrollbar.update(async?): void
ParamTypeDescription
asyncboolean, optionalForce an asynchronous update.

Forces scrollbar to update metrics.

By default, scrollbars are automatically updated with 100ms debounce (or childList changes if MutationObserver is supported). You can call this method to force an update when you modified contents inside scrollbar:

// append some contents to the scrollbar element...

// force an update
scrollbar.update();

// force an asynchronous update
scrollbar.update(true);

scrollbar.getSize()

scrollbar.getSize(): object

Return the size of scrollbar container element and scroll content element, it may be something like this:

{
    container: {
        width: 600,
        height: 400
    },
    content: {
        width: 1000,
        height: 3000
    }
}

scrollbar.setPosition()

scrollbar.setPosition(x, y): void
ParamTypeDescription
xnumberScrolling offset in x-axis.
ynumberScrolling offset in y-axis.

Likes the window.scrollTo() method, use this method to set the scrollbar to the given offset without easing:

// limit = { x: 500, y: 500 }
scrollbar.setPosition(100, 100);
console.log(scrollbar.offset); // { x: 100, y: 100 }

If the offset is out of limitation, it will be shrinked:

// limit = { x: 0, y: 100 }
scrollbar.setPosition(1024, 1024);
console.log(scrollbar.offset); // { x: 0, y: 100 }

scrollbar.scrollTo()

scrollbar.scrollTo(x, y, duration?, callback?): void
ParamTypeDescription
xnumberScrolling offset in x-axis.
ynumberScrolling offset in y-axis.
durationnumber, optionalEasing duration, default is 0 (non-easing).
callbackfunction, optionalCallback function that will be fired on the end of scrolling.

Scrolls to given position with quadratic easing function:

scrollbar.scrollTo(100, 100, 300, function (scrollbar) {
    // ...
});

scrollbar.addListener()

scrollbar.addListener(listener): void
ParamTypeDescription
listener(status) => voidScrolling event listener.

Since scrollbars will not fire a native scroll event, we need to registers thought scrollbar.addListener() method.

Notice: the callback functions will be invoked in every small scrolling, so be careful not to add time-consuming listeners that will slow down scrolling.

The status object contains following properties:

{
    direction: {
        // scrolling direction compares to the last offset
        x: 'none' | 'right' | 'left',
        y: 'none' | 'up' | 'down',
    },
    offset: {
        // current scrolling offset, equivalent to `scrollbar.offset`
        x: number,
        y: number,
    },
    limit: {
        // max-allowed scrolling distance, equivalent to `scrollbar.limit`
        x: number,
        y: number,
    }
}

scrollbar.scrollIntoView()

scrollbar.scrollIntoView(elem, options?): void
ParamTypeDescription
elemElementTarget element.
optionsobject, optionalScrolling options, see the table below.
Propertytypedefaultdescription
alignToTopbooleantrueWhether to align to the top or the bottom edge of container.
offsetTopnumber0Offset to top edge of container (used only if alignToTop is true).
offsetLeftnumber0Offset to left edge of container.
offsetBottomnumber0Offset to bottom edge of container (used only if alignToTop is false).
onlyScrollIfNeededbooleanfalseWhether to scroll container when target element is visible.

Scrolls the target element into visible area of scrollbar, like DOM method element.scrollIntoView(). This will be helpful when you want to create some anchors.

scrollbar.scrollIntoView(document.getElementById('a-section'), {
    offsetTop: 12,
    offsetLeft: 34,
    onlyScrollIfNeeded: true,
});

scrollbar.isVisible()

scrollbar.isVisible(elem): boolean
ParamTypeDescription
elemElementTarget element.

Checks if an element is visible in the current view area.

scrollbar.isVisible(document.getElementById('greet'))

scrollbar.infiniteScroll()

scrollbar.infiniteScroll(handler, threshold?): void
ParamTypeDescription
handler(status) => voidInfinite scrolling handler.
thresholdnumber, optionalRepresents the trigger offset to the bottom edge of current scrollbar, default is 50.

This is another useful method when you want to make infinite scrolling. Handlers will be invoked with the status object when you scrolling down over the given threshold:

instance.infiniteScroll(function (status) {
    // ...
}, 100);

scrollbar.stop()

scrollbar.stop(): void

Clears all pending movements and stops scrolling immediately.

// offset = { x: 0, y: 0 }
scrollbar.scrollTo(100, 100);
scrollbar.stop();

console.log(scrollbat.offset); // { x: 0, y: 0 }

scrollbar.destroy()

scrollbar.destroy(): void

Remove this scrollbar instance:

Before:

<section data-scrollbar style="overflow: hidden">
    <article class="scroll-content">
        ...
    </article>

    <aside class="scrollbar-track scrollbar-track-x">
        <div class="scrollbar-thumb scrollbar-thumb-x"></div>
    </aside>
    <aside class="scrollbar-track scrollbar-track-y">
        <div class="scrollbar-thumb scrollbar-thumb-y"></div>
    </aside>
</section>

After:

<section data-scrollbar>
    ...
</section>

Common mistakes

Initialize a scrollbar without a limited width or height

Likes the native scrollbars, a scrollable area means the content insides it is larger than the container itself, for example, a 500*500 area with a content which size is 1000*1000.

Therefore, it necessary to set the width or height for the container element:

#my-scrollbar {
    width: 500px;
    height: 500px;
    overflow: auto;
}

FAQ

How to listen to the scroll event?

Since scrollbars will not fire a native scroll event, we need to registers thought scrollbar.addListener() method:

scrollbar.addListener(function (status) {
    // ...
});

Related Projects

Contributing

  • Create an issue with an example on jsbin.com, including latest version of smooth-scrollbar through:

    <link rel="stylesheet" href="https://unpkg.com/smooth-scrollbar@latest/dist/smooth-scrollbar.css">
    
    <script src="https://unpkg.com/smooth-scrollbar@latest/dist/smooth-scrollbar.js"></script>
  • Run your forks locally with following steps:

    1. Clone the repo: git clone https://github.com/idiotWu/smooth-scrollbar.git,
    2. Install dependencies: npm run install,
    3. Start server: npm start.

Before making pull requests, make sure you have run npm test!

License

MIT.