Sticky figure with scrollama

This is a dissection of Russell Samora’s scrollama sticky-side example, which is also on github under the “main” repository (as of Sep 2023).

Russell Samora made scrollama to use the intersection observer API in favor of scroll events, with excellent results. As stated in MDN, the API: ‘… observes changes in the intersection of target elements with an ancestor element or with a top-level document’s viewport’.

As of 2023, scrollama was still maintained and included over 20 contributors, with version 3 already available.

The code

The first that the original author of the demo did was to instatiate all the libraries used in the example:

D3.js

D3.js is used in this example mostly to facilitate the DOM manipulation but it is also a pre-entry to explain the use of D3.js (it could be any other library though)

142
143
144
145
146
    
var main = d3.select('main')
var scrolly = main.select('#scrolly');
var figure = scrolly.select('figure');
var article = scrolly.select('article');
var step = article.selectAll('.step');
    

With D3.js the author selected and named the main HTML elements that will characterize the animation:

  • A main HTML element enclosing all other elements that will be animated
  • A HTML section with an ID with scrolly as value
  • A HTML figure tag, having the area that will be “sticked”
  • A div, which was an article tag in the original code
  • A list of divs children of the HTML article all of class step with a digit from 1 to 4 as value for their corresponding data-step attributes

scrollama

149

var scroller = scrollama();

The scrollama instance was called within several functions in the code:

  • In a resizing function, handleResize, where scrollama instance (scroller) was called to update the dimensions of the HTML elements that would be eventually registered on it.
152
...
164
165
166

function handleResize() {
    ...
   // 3. tell scrollama to update new element dimensions
	scroller.resize();
}

  • The init function, where the variable scroller is setup
...
182
...
190
191
192
193
194
195
196
197
...

...
function init() {
    ...
   // 3. bind scrollama event handlers (this can be chained like below)
    scroller.setup({
        step: '#scrolly article .step',
        offset: 0.33,
        debug: false,
    })
        .onStepEnter(handleStepEnter)
}
...

In the example, setting up the values of 3 scroller properties were required:

  • The step property, which get as value(s) the target HTML elements that will be subject to animation; in our case are all those classed as step
({
    step: '#scrolly article .step',
    ...
})
  • The offset property, which is the “location” of the intersection observer somewhere on the viewport. Once the target element crosses the offset, scrollama will add an is-active class to it, and it will remove it from any other target that is already handled.
({
    ...
    offset: 0.33,
    ...
})
  • Passing a custom event handler callback function, handleStepEnter, containing the actions to be taken every time the offset is crossed. In this case it was assigned to scrollama onStepEnter (there are other options). This was the callback function:
168
169
170
171
172
173
174
175
176
177
178
179
180
...

// scrollama event handlers
function handleStepEnter(response) {
    console.log(response);			
    // response = { element, direction, index }

    // add color to current step only
    step.classed('is-active', function (d, i) {
        return i === response.index;
    })
			
    // update graphic based on step
	figure.select('p').text(response.index + 1);
}
...

The scrollama onStepEnter event handler functionality passes a response parameter to your custom callback function holding information about the DOM status ({ element, direction, index }), allowing you to set different scenes using, for example, if-else statements.

In Action

The example by Russell Samora used the response’s index property to change color and modify the value of a “figure”:

This div with a gold background has a class 'step' and just crossed an offset of 33% of your viewport calculated from top to down.

This is the second target that cross the offset. Everytime a target crosses the offset, its index is passed as value to be shown in the figure container.

The index is a property hold by a response that is passed from scrollama into your animation handler (eg. the handleStepEnter).

Every time that a target passes the offset, an is-active class is assigned to it.

0

So… What did we learn from this code?

It seems that when what you want is to change the status of your page based on up/down scrolling, the use of scrollama seems to be easier and natural. That, at least, was my impression. The use of a simple offset of the viewport based on the intersection observer API might be much more convenient for several cases.

The package makes use of very simple settings, and that also affects the custom code you want to use for handling events. A simple event handler callback with if-else statements is something very appealing if you are looking to keep things simple.

And in case you need some help identifying where the offset is placed on your device viewport, scrollama has a debug setup that shows you a line crossing the offset. In our example, you just have to set debug to true:

182
...
189
190
...
194 
195
...
197
...
function init() {
    ...
   // 3. bind scrollama event handlers (this can be chained like below)
    scroller.setup({
    ...
        debug: true,
    })
    ...
}
    ...

scrollMagic and other packages using scroll events are harder to set. However, they seem to offer more possibilities and they might be more appropriate for situations where a more advanced animation is required. For example, I don’t know if scrollama could be easy to use when the reposition of an HTML element is the trigger of another event.

Final remarks

A more detailed post dated back to 2017 about the Russell Samora’s sticky side demo could be found at The Pudding, which includes a better description of the “sticky graphic pattern” and gives a look at the css used in the demo. (Observation: the post assumes the use of jQuery for the javascript part)

There are many examples out there using scrollama. A simple one I came across while looking for some was this one by Erik Driessen. Like me, Erik is interested in the use of this tools for storytelling and also incorporates D3.js in his demos. Just like I did, the code by Erik’s appears to be based on the Russell Samora’s demos but Erik goes a bit further by including more D3.js animations.

And that’s it! I hope you found this post useful for your projects. I think I will be using scrollama myself for some of my post in the future. Meanwhile, happy coding!