Simple Scroll Snapping Carousel (Flexbox Layout / Grid Layout)

Here are two small scroll-snapping carousels that I made. In the top one the items are laid out using CSS Flexbox, whereas the second one uses CSS Grid.

The code also works fine with arbitrarily sized .scroll-items elements, they don’t need to have the same width.

ℹ️ Want to now more about scroll snapping? Check out Well-Controlled Scrolling with CSS Scroll Snap by Google, and Practical CSS Scroll Snapping on CSS Tricks.

πŸ˜…Great to see that CSS Scroll Snapping moved away from the snapList, as first proposed in 2013.

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

β˜•οΈ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Delighters.JS – Add CSS animations to delight users as they scroll down

Nice little library by Martin Kool / Q42.

Delighters.js toggles classnames as you scroll. You do the rest!

πŸ€“ Late 2013 I created a likewise thingy (dependent on jQuery) πŸ™‚

The main class toggled is .delighter, with an extra .started or .ended to know if the animation just started or ended.

   /* when the library loads, each [data-delighter] 
      gets the .delighter class */

   .foo.delighter {
      transition: all .3s ease-out;
      transform: translateX(-100%);
      opacity: 0;

   /* the .started class is set when the top
      of [data-delighter] is at 0.75 of the viewport 
      (where 0 is top and 1 is bottom) */

   .foo.delighter.started {
      transform: none;
      opacity: 1;

   /* an extra .ended state is set when the bottom 
      of [data-delighter] is at 0.75 of the viewport
      (where 0 is top and 1 is bottom) */

   .foo.delighter.started.ended {
      border: solid red 10px;

Delighters.js →

Scrollama – Scrollytelling with IntersectionObserver

Scrollama is a modern & lightweight JavaScript library for scrollytelling using IntersectionObserver in favor of scroll events.

The code that accompanies the markup pictured above:

// instantiate the scrollama
const scroller = scrollama();

// setup the instance, pass callback functions
    container: '.scroll', // wrapping container
    step: '.scroll__text .step', // all steps
    graphic: '.scroll__graphic', // the sticky element
    offset: 0.5, // optional, default = 0.5

Scrollama →

Customizing Pull-to-Refresh and Overflow Effects with CSS’ overscroll-behavior

Next to dynamic imports, another feature that landed in Chrome 63 is CSS overscroll-behavior:

Scrolling is one of the most fundamental ways to interact with a page, but certain patterns can be tricky to deal with. For example, the browsers pull to refresh feature, where swiping down at the top of the page, does a hard reload.

In some cases, you might want to override that behavior and provide your own experience.

The CSS overscroll-behavior property allows you to do just that: override the default scroll behavior. With it you can prevent a full reload when a pull-to-refresh gesture is performed (and inject your own logic), disable rubber banding (no more for need this nasty hack), etc.

Another typical use case is one where you have a scrollable piece of content that is layed out above another scrollable piece of content – yes: a modal. The default behavior is that when reaching the scroll boundary of the modal, the content underneath it starts to scroll:

Setting overscroll-behavior: contain; on the modal will prevent this default behavior, resulting in a better experience :

overscroll-behavior is available in the new Chrome 63 and in Firefox (ever since version 36!). Other browsers currently don’t support this.

Here’s a pen:

See the Pen
overscroll-behavior: contain
by Aaron Iker (@aaroniker)
on CodePen.

Take control of your scroll: customizing pull-to-refresh and overflow effects →

Using Intersection Observers

With the Intersection Observer coming to Firefox, a nice article covering it appeared on Mozilla Hacks.

The IntersectionObserver interface of the Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.

To use it, create a new instance of IntersectionObserver, and then let it observe a given element (target):

let observer = new IntersectionObserver((entries, observer) => { /* … */});
observer.observe(target); // <-- Element to watch

Here's a demo pen:

See the Pen Hello IntersectionObserver by Dan Callahan (@callahad) on CodePen.

To not watch the target's relation to the viewport, but to another element, use the root option.

let observer = new IntersectionObserver((entries, observer) => { /* … */}, {
   root: parentElement,
observer.observe(target); // <-- Element to watch

Works in Edge 15, Chrome 51, and soon Firefox 55. For browsers that don't support it you can use a polyfill.

Intersection Observer comes to Firefox →
IntersectionObserver Polyfill →

AOS – Animate on Scroll


AOS allows you to animate elements as you scroll down, and up. If you scroll back to top, elements will animate to it’s previous state and are ready to animate again if you scroll down.

By setting data-aos-* attributes on your HTML elements, you can define which animation to use, what timing to use, etc.

<div class="some-item" data-aos="fade" data-aos-duration="500">Example Element</div>

See the Pen AOS – animations by Snik (@michalsnik) on CodePen.

Don’t want to include AOS entirely? Only want to know the essence of how stuff like this works? Then check out the Scroll Animations pen I’ve built quite some time ago.

AOS Demo →
AOS Source →
AOS Introductory Post (CSS Tricks) →

CSS Only Scroll Indicator

There’s a pen embedded in this post. Visit this post on the website, or see the Pen CSS only scroll indicator on CodePen.

I was interested to see if I could make a scroll indicator with just CSS. You can! But maybe you shouldn’t. This is an interesting consequence of a bunch of hacks held together with duct tape. It uses z-index hacks, gradient hacks and tricks with calc and viewport units.

Fiddling with the CSS used I can confirm that even though we can, we maybe shouldn’t …

CSS Only Scroll Indicator →

Prevent overscroll/bounce in iOS MobileSafari and Chrome (CSS only)

UPDATE 2017.12: For non-Safari browsers you can use overscroll-behavior to solve exactly this. Simply apply overscroll-behavior-y: none; on the <body> and be done with it.

Safari however still requires the workaround detailed below …

Know this bouncy overscrolling behaviour that browsers have been doing whenever you reach the β€œedge” of the page its contents?

elastic-scrolling, with bounce scroll

Sometimes – in fullscreen apps for example – you’ll want to disable this. Now, there’s no need to resort to JavaScript and hijack touchstart, as the little CSS snippet below can prevent the rubber band scrolling:

body {
  position: fixed;
  overflow: hidden;

Tested with iOS8, iOS9, and iOS10.

However, as this snippet disables *all* scrolling on the body, if you want to retain scrolling on your page (but now without the overscroll effect) you’ll want to make use of a scrollable wrapper that spans the entire window/screen and which wraps around your entire content. Like so:

  <div class="mainwrapper">
body > .mainwrapper {
  width: 100vw;
  height: 100vh;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch; /* enables β€œmomentum” (smooth) scrolling */

You’ll most likely want to remove the margin and padding from the body too in that case πŸ˜‰

Note that your mileage may vary. Other pure CSS solutions do exist (untested though)

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

β˜•οΈ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

rafscroll – chain your scroll events to requestAnimationFrame

new rafscroll(function() {
  // Do your thing here.

Your monitor refreshes at 60 frames per second (fps). Scroll events, on the other hand, do not. Chaining your scroll events to a requestAnimationFrame ensures that your transitions and animations will refresh each time the monitor refreshes, rather than each time a scroll event is fired.

rafscroll – chain your scroll events to requestAnimationFrame

Not too sure how this works? Leaner, Meaner, Faster Animations with requestAnimationFrame is a great article on this subject.