Skip to content
jQuery plugin for one-directional scrolling with item based navigation support.
Find file
Pull request Compare This branch is 278 commits behind darsain:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
css
img
js
README.md
compress.sh
index.html
jquery.sly.js
jquery.sly.min.js

README.md

Sly

jQuery plugin for one-directional scrolling with item based navigation support.

See the DEMO

Dependencies

Except jQuery, there are no other dependencies. That means you don't need 200kB of jQuery-UI to slide a few items. Just this nice 9KB (minified) action - you are welcome :)

Compatibility

Works everywhere! I'm afraid even in IE6 (not intended, honest). Mobile is not tested.

Sly upholds the Semantic Versioning Specification, and right now is in beta. For more info, read the Roadmap below.

Roadmap

This plugin is in development! and the API may change before the 1.0.0 release.

To do before 1.0.0:

  • Exchanging jQuery.animate for highly optimized custom animation rendering for silky-smoothness.
  • Navigation by clicking on scrollbar.
  • Extending events with jQuery.Callbacks API.

Maybe in 1.0.0, maybe later:

  • Touch events support.

Layout & requirements

Terminology

Sly is being applied to a FRAME. SLIDEE is a first child of a FRAME. The content/items are than inside of a SLIDEE.

FRAME should have no padding in a corresponded sly direction (padding left & right for horizontal, and padding top & bottom for vertical navigation), and SLIDEE should have no margin in a corresponded sly direction (margin left & right for horizontal, and margin top & bottom for vertical navigation). You can apply padding to SLIDEE, or margins to items, (sly accounts for this), but do not use any other units than pixels, or you'll bork things.

If you are not using one of the item based navigation logics, the content can be anything:

<div id="frame">
    <div class="slidee">
        <h2>This in here...</h2>
        <p>...can be anything. <strong>Anything!</strong></p>
    </div>
</div>

Otherwise, you need a strict list of items, like:

<div id="frame">
    <ul class="slidee">
        <li></li> // Item
        <li></li> // Item
        <li></li> // Item
    </ul>
</div>

But the actual tags are not enforced. Dividitis is not discriminated :)

Calling

$frame.sly( [ options [, returnInstance ]] );

[options]

Sly type

horizontal: default: 0 Set to 1 to change the sly direction to horizontal.

itemNav: default: 0 Type of item based navigation logic. Can be:

  • 0: disabled No item based navigation, just a usual scrolling.
  • basic: Items in SLIDEE snap to edges.
  • smart: Same as basic, but activated item close to, or outside of the edge will be positioned to the opposite edge to help with further navigation.
  • centered: Activated items are positioned to the center of a visible frame when possible.
  • forceCentered: Active items are always centered & centered items are always active. Every change in position activates item that is right now in the center of a FRAME. With this navigation type, each item is considered to be a separate page, so each item receives a page button in pages bar.
Scrollbar

scrollBar: default: null Selector or DOM element for scrollbar container (scrollbar should have one child element representing scrollbar handle).

dynamicHandle: default: 1 Resizes scrollbar handle to represent the size of a SLIDEE in proportion to FRAME. Set to 0 to leave it to CSS.

dragHandle: default: 1 Set to 0 to disable dragging of a scrollbar handle.

minHandleSize: default: 50 Minimal size of a handle in pixels.

Pages bar

pagesBar: default: null Selector or DOM element for pages bar container.

pageBuilder: default: function Function that returns HTML for one page item. Arguments: function (index) {} (index starts at 0)

Navigation buttons

prev: default: null Selector or DOM element for a "previous item" button. Irrelevant in non-item based navigation.

next: default: null Selector or DOM element for a "next item" button. Irrelevant in non-item based navigation.

prevPage: default: null Selector or DOM element for a "previous page" button.

nextPage: default: null Selector or DOM element for a "next page" button.

Automated cycling

cycleBy: default: 0 Enable automated cycling by 'items', or 'pages'.

cycleInterval: default: 5000 Number of milliseconds between cycles.

pauseOnHover: default: 1 Pause cycling when mouse hovers over a frame.

startPaused: default: 0 Set to "1" to start in paused state.

Mixed options

scrollBy: default: 0 Enable mouse scrolling by this many pixels, or (in item-based navigation) items.

dragContent: default: 0 Enable navigation by dragging the SLIDEE with a mouse.

elasticBounds: default: 0 When dragging past limits, stretch them a little bit (like on smart-phones).

speed: default: 300 Animations speed. Set to 0 to disable animation.

easing: default: 'swing' Animations easing. Can be 'linear', or 'swing'. For more, install the jQuery Easing Plugin.

scrollSource: default: null Selector or DOM element for catching the mouse scroll events. By default, FRAME is used.

dragSource: default: null Selector or DOM element for catching the mouse dragging events. By default, FRAME is used.

startAt: default: 0 Starting offset in **pixels* or (in item-based navigation) items. Items index starts at 0.

keyboardNav: default: 0 Enable navigation with keyboard arrows (left & right for horizontal, up & down for vertical).

Note: Keyboard navigation will disable page scrolling with keyboard arrows in a correspondent sly direction.

Classes

draggedClass: default: 'dragged' Class name for scrollbar handle, or SLIDEE when they are being dragged.

activeClass: default: 'active' Class name for active item.

disabledClass: default: 'disabled' Class name for disabled buttons. (e.g.: "Previous item" button when first item is selected)

[ returnInstance ]

Boolean argument requesting to return a plugin instance instead of a chainable jQuery object. You can than use all methods documented below directly on this instance.

If Sly is called on more than one element, it returns a plugin instance for a first element in set.

Methods

Sly has a bunch of very useful methods that provide almost any functionality required. You can call them via .sly() proxy, or directly on a plugin instance. You can get the instance by:

Passing true into the returnInstance argument.

var frame = $('#frame').sly(options, true);

Or by retrieving it from a FRAME element data.

var frame = $('#frame').sly(options).data('sly');

You can than call all methods directly.

frame.activate(2);

Activate

$frame.sly('activate', item);

Activates an item, and depending on a navigation type, repositions it. Irrelevant in non-item based navigation.

item: Index or DOM element of an item in SLIDEE that should be activated.

ActivatePage

$frame.sly( 'activatePage', index );

Activates a page.

index: Index of a page that should be activated, starting at 0.

Cycle

$frame.sly( 'cycle' );

Starts automated cycling.

Pause

$frame.sly( 'pause', [ soft ] );

Pause automated cycling.

soft: Pass true to use soft pause - pause that will be canceled when mouse hovers out of the frame. Used internally for pauseOnHover functionality.

Toggle

$frame.sly( 'toggle' );

Start when paused, or pause when cycling.

Destroy

$frame.sly( 'destroy' );
// or alias
$frame.sly( false );

Removes sly instance, resets positions, and unbinds all attached events.

Next

$frame.sly( 'next' );

Activates next item. Irrelevant in non-item based navigation.

Prev

$frame.sly( 'prev' );

Activates previous item. Irrelevant in non-item based navigation.

NextPage

$frame.sly( 'nextPage' );

Activates next page. When forceCentered navigation is used, this is a mere alias of a next method.

PrevPage

$frame.sly( 'prevPage' );

Activates previous page. When forceCentered navigation is used, this is a mere alias of a prev method.

Reload

$frame.sly( 'reload' );

Reloads sly instance. Call it if any change has happened to SLIDEE content, like things have been appended, removed, or resized.

Set

$frame.sly( 'set', [ propertyName/object [, value ] ] );

Updates one, or multiple values in a sly options object.

$frame.sly( 'set', 'speed', 0 ); // Updates one property in options object
$frame.slt( 'set', { speed: 0, cycleInterval: 0 } ) // Extends current options object with new values

Right now only a simple options can be updated (like speed, cycleInterval, class names ...).

ToCenter

$frame.sly( 'toCenter' [, target ] );

Animates target to the center of a visible frame. When no target is passed, it will animate whole SLIDEE to the center.

target: In item based navigation, it can be an item index, or an item DOM element. In content based scrolling, it can be a selector or a DOM element inside of SLIDEE.

You can use this method even when *itemNav** is disabled, targeting random items from content, like headings, paragraphs, ...*

ToStart

$frame.sly( 'toStart' [, target ] );

Animates target to the start of a visible frame. Doesn't work when any type of centered item navigation is used. When no target is passed, it will animate whole SLIDEE to the start.

target: In item based navigation, it can be an item index, or an item DOM element. In content based scrolling, it can be a selector or a DOM element inside of SLIDEE.

You can use this method even when *itemNav** is disabled, targeting random items from content, like headings, paragraphs, ...*

ToEnd

$frame.sly( 'toEnd' [, target ] );

Animates target to the end of a visible frame. Doesn't work when any type of centered item navigation is used. When no target is passed, it will animate whole SLIDEE to the end.

target: In item based navigation, it can be an item index, or an item DOM element. In content based scrolling, it can be a selector or a DOM element inside of SLIDEE.

You can use this method even when *itemNav** is disabled, targeting random items from content, like headings, paragraphs, ...*

Custom events

On almost any action sly does, there is an event being triggered. All custom events receive similar arguments: $items, position, and relatives.

$items: argument is jQuery wrapped array of items. Empty when non-item based navigation is used.

position: object with information about a current SLIDEE position. Structure:

{
    cur: 200,  // current SLIDEE position
    max: 4000, // maximum limit for SLIDEE position
    min: 0     // minimum limit for SLIDEE position
}

relatives: this object provides indexes of items in SLIDEE relative to a visible view of a FRAME, as well as a bunch of other useful info. Structure:

{
    activeItem: 3,    // current active idem index
    activePage: 0,    // current active page index
    centerItem: 2,    // item lying in center of a visible FRAME
    firstItem: 0,     // first completely visible item in a FRAME
    frameSize: 940,   // FRAME size in a direction of current sly (horizontal: width, vertical: height)
    handleSize: 157,  // scrollbar handle size in a direction of a current sly (horizontal: width, vertical: height)
    items: 30,        // total number of items
    lastItem: 4,      // last completely visible item in a FRAME
    pages: 6,         // number of pages
    sbSize: 940,      // scrollbar size in a direction of a current sly (horizontal: width, vertical: height)
    slideeSize: 5640  // SLIDEE size in a direction of a current sly (horizontal: width, vertical: height)
}

sly:load

Event triggered on FRAME after first sly load, and after each realod method call.

$frame.on( 'sly:load', function( event, position, $items, relatives ){ ... } );

NOTE: position argument in this event also contains an old property, specifying the position values before reload. The position object than looks like this:

{
    cur: 100,
    max: 120,
    min: 0,
    old: {
        cur: 100,
        max: 100,
        min: 0
    }
}

sly:active

Event triggered on an item that has just been activated.

$item.on( 'sly:active', function( event, $items, relatives ){ ... } );

sly:dragStart

Event triggered on a SLIDEE or a scrollbar handle on dragging start.

$slidee.on( 'sly:dragStart', function( event, position ){ ... } );
$sbHandle.on( 'sly:dragStart', function( event, position ){ ... } );

sly:drag

Event triggered on a SLIDEE or a scrollbar handle on dragging.

$slidee.on( 'sly:drag', function( event, position ){ ... } );
$sbHandle.on( 'sly:drag', function( event, position ){ ... } );

sly:dragEnd

Event triggered on SLIDEE or scrollbar handle on dragging end.

$slidee.on( 'sly:dragEnd', function( event, position ){ ... } );
$sbHandle.on( 'sly:dragEnd', function( event, position ){ ... } );

sly:move

Event triggered on a FRAME on every SLIDEE move. This is triggered right before the animation start, but the arguments represent the state of FRAME/SLIDEE/items when the animation will be finished.

$frame.on( 'sly:move', function( event, position, $items, relatives ){ ... } );

sly:moveEnd

Event triggered on FRAME on every SLIDEE move. This is triggered after animation has finished.

$frame.on( 'sly:moveEnd', function( event, position, $items, relatives ){ ... } );

sly:nav

Event triggered on each navigation change, like prev, next, prevPage, ...

This event is not triggered when SLIDEE or a scrollbar handle are being dragged, but it is triggered on alignment, i.e. when mouse has been released, and items need to be aligned to the FRAME edges. Obviously that doesn't happen in non-item based navigation.

$frame.on( 'sly:nav', function( event, position, $items, relatives ){ ... } );

sly:cycleStart

Triggered on each cycle initialization, e.g. on sly load with cycling enabled, and every time you un-pause cycling by moving your mouse outside of the frame, or trigger the cycle method.

$frame.on( 'sly:cycleStart', function( event, position, $items, relatives ){ ... } );

sly:cycle

Triggered on each cycle right after the animation starts. It is essentially an equivalent of sly:move event, but triggered only when auto cycling.

$frame.on( 'sly:cycle', function( event, position, $items, relatives ){ ... } );

sly:cyclePause

Triggered when cycling has been paused, whether it was by mouse hovering over FRAME, or by pause method.

$frame.on( 'sly:cyclePause', function( event, position, $items, relatives ){ ... } );

Example of a call with all default options

$frame.sly({
    // Sly type
    horizontal:      0,
    itemNav:         0,

    // Scroll bar
    scrollBar:       null,
      dynamicHandle: 1,
      dragHandle:    1,
      minHandleSize: 50,


    // Pages bar
    pagesBar:        null,
      pageBuilder: function( index ){
          return '<li>'+(index+1)+'</li>';
        },

    // Navigation buttons
    prev:            null,
    next:            null,
    prevPage:        null,
    nextPage:        null,

    // Automated cycling
    cycleBy:         0,
      cycleInterval: 5000,
      pauseOnHover:  1,
      startPaused:   0,

    // Mixed options
    scrollBy:        0,
    dragContent:     0,
      elasticBounds: 0,
    speed:           300,
    easing:          'swing',
    scrollSource:    null,
    startAt:         0,
    keyboardNav:     0,
    keyboardNavByPages: 0,

    // Classes
    draggedClass:  'dragged',
    activeClass:   'active',
    disabledClass: 'disabled'
});

Notable behaviors

  • When using item based navigation, you can go wild with your items. Each one can be of different size, and have different margins & paddings. Sly is smart, and can figure it out :)

  • When forceCentered item navigation is used, every item is considered to be a separate page. That's so the pages bar could render page button for each item. Check the forceCentered horizontal examples in demo page. Also, the nextPage & prevPage methods in this case do the exact same thing as next & prev methods.

  • When margin of a first item (margin-top for vertical, margin-left for horizontal) is 0, the last margin of last item is ignored, and SLIDEE wont go past the last item border-box. Thats so you don't have to fix last item margins with li:last-child { margin-right: 0; }, or class on last child to support older browsers when you want only spaces between items, but not between first/last item and a SLIDEE border.

Contributing

Contributions are welcome, but there are some rules:

  • Maintain the coding style used in the project.
  • The resulting code has to pass JSHint with options defined in the header.
Something went wrong with that request. Please try again.