Posted by Scott Jehl 06/15/2016

Everybody loves carousels, am I right?

[…entire room empties out…]

But really though, hear me out! We use carousels on many projects and they’re good for a great many things. One of those things is presenting product images neatly within an already-noisy product detail page, say, for some Potted Meat on Amazon. Another of those things is, well okay I can’t really think of another example but… again, that first one!

At any rate, if you’re going to use a carousel, it had better work great. For years, we’ve been improving our own Responsive Carousel to meet the needs of our client projects, and it still serves us well (particularly when we want more of a crossfading slideshow effect). Recently however, we started looking into a new web standard which is specifically designed to handle the sidescrolling carousel pattern. That new standard is CSS Snap Points, and it extends the functionality of CSS “overflow” scrolling regions to be able to “snap” to particular points in their scrolling span.

CSS Snap Points in action #

To see CSS Scroll Snapping in action, I recommend checking out this Webkit blog post that has a bunch of videos and examples. You’ll need either Firefox, Safari, MS IE or Edge to see the demos working fully (no Chrome support, sadly), but the feature does fall back to ordinary scrolling in unsupporting browsers.

In code, CSS snap points are rather nice, at least compared to what we’d do otherwise. For example, here’s how you’d style a simple scroll-snapping container that has 4 image “slides”, each filling 25% of their parent element’s width, which is 400% of the width of scrollable element. It will “snap” to the start of the slides when the user scrolls it:

HTML:

<div class="scrollpane"> <div class="scrollpane_items"> <img class="scrollpane_item" alt="..." src="1.jpg"> <img class="scrollpane_item" alt="..." src="2.jpg"> <img class="scrollpane_item" alt="..." src="3.jpg"> <img class="scrollpane_item" alt="..." src="4.jpg"> </div> </div>

CSS:

.scrollpane { overflow: auto; white-space: nowrap; width: 100%; -webkit-overflow-scrolling: touch; /* snap to points */ -webkit-scroll-snap-type: mandatory; -ms-scroll-snap-type: mandatory; scroll-snap-type: mandatory; /* x interval for snapping (100% of container width) */ -webkit-scroll-snap-points-x: repeat(100%); -ms-scroll-snap-points-x: repeat(100%); scroll-snap-points-x: repeat(100%); } .scrollpane_items { width: 400%; overflow: hidden; } .scrollpane_item { width: 25%; float: left; }

JavaScript:

// none! just kidding... keep reading.

Polyfills and ProllyShouldWorks #

For basic use cases, the above example works pretty well. And if you’re okay with a carousel component only snapping in browsers that support CSS snap points (your client probably will not be), then that’s pretty much all you need!

For our purposes, we wanted to use this on a popular ecommerce website, so we needed something a bit more refined. We wanted snapping to work more broadly in browsers that don’t yet support it natively, and we also wanted to integrate features like thumbnail navigation, and next and previous arrows, which tend to help a lot in browsers that don’t show a scrollbar for overflow regions. We also noticed that even in supported browsers, the behavior was not fully what we desired. For example, we wanted our navigation controls (thumbnails and next/prev links) to scroll the carousel smoothly to the target slide, rather than jumping to the slide immediately. We also wanted to maintain a snap location while resizing the browser, and that did not yet work in any implementations we tested.

Introducing Snapper #

When in trouble, throw some JavaScript at it, right?

Snapper is a lightweight script that’ll apply CSS and JS carefully to create a broadly-functional snap-points carousel. This script builds on a simple overflow container and native CSS snap points to make it better by:

feature-testing for CSS Snap Points support and polyfilling the behavior for browsers that don’t support it

Adding a smooth side scroll animation when you navigate (even in browsers that natively support snap points)

Improving navigation by adding optional next/prev buttons, and supporting thumbnail or dot navigation links

Adding the ability to loop back to the start of the carousel when you reach the end

Demos, Code, and Issue Tracker #

Demos: You can view several demos of Snapper at the project repo, here: Snapper Demos

Docs: Find docs in the project repo, here: Snapper Demos

Code: The code is on Github and NPM

Issue tracker: if you run into problems or have ideas, feel free: Snapper Issues

Note: Due to the project requirements for which Snapper was developed, it does have a jQuery (or Shoestring) dependency. We’re very open to refactoring it to remove that dependency as time allows, and would love some help in doing so. So far, the unit tests are largely written to test the outcomes rather than the API, so that may make for an easier transition to “vanilla” JS.

Thanks for reading, and do hit us up on twitter with any feedback or questions you may have.

All blog posts