Scrollstory
A jQuery plugin for building scroll-based stories
Install / Use
/learn @sjwilliams/ScrollstoryREADME
ScrollStory
ScrollStory is a jQuery plugin for building scroll-based stories. Rather than doing a specific task, it aims to be a tool to help solve general problems.
For example, it can help you update your nav as you scroll down the page. It can auto-scroll to sections of your story on a mouse click or custom event. It can trigger custom callbacks that manipulate the page as you scroll, like lazy loading media. It can dynamically insert markup into the page using an array of data on instantiation, or use pre-existing markup. Additionally, it maintains data associated with all these custom interactions.
Examples
- Controlling scroll-based graphic in 111 N.F.L. Brains. All But One Had C.T.E., nytimes.com
- Triggering zoomy photo in Fleeing Boko Haram, Thousands Cling to a Road to Nowhere, nytimes.com
- Triggering animations in the desktop version of This Is Your Life, Brought to You by Private Equity, nytimes.com
- ScrollStory compared in How to implement scrollytelling with six different libraries, pudding.cool
- Lazy loading 360º video in 52 Places to Go in 2017, nytimes.com
- Revealing text in A Gift to New York, in Time for the Pope, nytimes.com
Overview
ScrollStory is built on the idea that scrolling stories often comprise discrete elements stacked on a page that exclusively require a reader’s focus. These elements — or items in ScrollStory speak — can be anything: sections of text (like the sections of this page), a video, a photo and caption, or any HTML element that can be scrolled to.
ScrollStory follows these items, internally tracking the scroll distance until an item requires the reader’s focus, at which point custom code can be executed to manipulate the experience, like updating the navigation bar and fading the background color on this page. Additionally, custom code can be run whenever any item enters the viewport; any item within a ScrollStory collection is activated (or, inversely, when none are activated); when an item is filtered, a ScrollStory construct meaning it is no longer an active part of a collection; or any of 17 custom events.
ScrollStory items aren't just DOM nodes. Rather, they’re data objects that have a corresponding representation in the DOM. ScrollStory instances maintain data about each item object in a collection and provides numerous methods of accessing, querying and modifying that data.
Documentation
Download
- Development
- Production
npm install scrollstory
Basic Usage
In its most basic form, ScrollStory takes a container element and searches for .story child elements.
The code:
<body>
<!-- Default markup style -->
<div id="container">
<div class="story"><h2>Story 1</h2><p>...</p></div>
<div class="story"><h2>Story 2</h2><p>...</p></div>
</div>
<!-- include jquery and scrollstory -->
<script src="jquery.js"></script>
<script src="jquery.scrollstory.js"></script>
<script>
// Instantiation
$(function(){
$("#container").scrollStory();
});
</script>
</body>
Internally, ScrollStory turns those elements into item objects and assigns them several default properties, like its index position in the list, its inViewport status and a data object for user data.
The item object:
{
id: 'story0-2', // globally unique across every instance of ScrollStory. User-assigned or auto generated.
index: 0, // zero-based index for this item within this instance of ScrollStory
el: $(), // jQuery object containing the item node
data: {}, // user data for this item
inViewport: true,
fullyInViewport: false,
active: false, // is this the exclusively active item
filtered: false, // has this item been removed from the collection
category: 'people', // optional. single, top-level association.
tags: ['friend', 'relative'], // optional. array of strings defining lose relationships between items.
distanceToOffset: -589, // px distance to global trigger,
adjustedDistanceToOffet: -589, //px distance to trigger taking into account any local adjustments for this item
scrollStory: {}, // reference to the scrollstory instance this item belongs to
height: 582, // item element height
width: 1341, // item element width
scrollOffset: false, // a number if the scrollOffset for this item is different from the global one
triggerOffset: false // a number if the triggerOffset for this item is different from the global one
}
In addition to creating item objects on instantiation, ScrollStory modifies the DOM to reflect various states.
- A class of
scrollStoryis added to the container element. - A class of
scrollStoryActiveis added to the container element if any item is active. - A class of
scrollStoryActiveItem-{itemId}is added to the container element to reflect currently "active" item. - A class of
scrollStoryItemis added to every item element. - A class of
activeis added to the currently active item element. - A class of
inviewportis added to item elements partially or fully in the viewport. - An ID attribute is added to any story item element that didn't have one.
Post-instantiation DOM
<div id="container" class="scrollStory scrollStoryActive scrollStoryActiveItem-story0-0">
<div id="story0-0" class="story scrollStoryItem inviewport active ">...</div>
<div id="story0-1" class="story scrollStoryItem inviewport">...</div>
<div id="story0-2" class="story scrollStoryItem">...</div>
<div id="story0-3" class="story scrollStoryItem">...</div>
</div>
Pass In Data Via Attributes
Data can be dynamically added to individual item objects by adding it as data attributes in markup. Combined with ScrollStory's API methods, some very dynamic applications can be built.
The code:
<div id="container">
<div class="story" data-organization="The New York Times" data-founded="1851"></div>
<div class="story" data-organization="The Washington Post" data-founded="1877"></div>
...
</div>
<script>
$(function(){
$("#container").scrollStory();
});
</script>
Internally, ScrollStory turns those elements into item objects and assigns them several default properties, like its index position in the list, its inViewport status and a data object for user data.
The <span code>item</span> objects:
[{
id: 'story0-0',
index: 0
inViewport: true,
active: true,
...
data: {
organization: "The New York Times",
founded: "1851"
}
},{
id: 'story0-1',
index: 1
inViewport: false,
active: false,
...
data: {
organization: "The Washington Post",
founded: "1877"
}
}]
Post-instantiation
<div id="container" class="scrollStory scrollStoryActive scrollStoryActiveItem-story0-0">
<div id="story0-0" class="story scrollStoryItem inviewport active" data-organization="The New York Times" data-founded="1851">...</div>
<div id="story0-1" class="story scrollStoryItem" data-organization="The Washington Post" data-founded="1877">...</div>
</div>
Build From Data
A ScrollStory instance can be built with an array of data objects instead of markup, which will be used to generate all the ScrollStory items and elements on the page. The items array and rendered markup are idential to the example above.
The Code
$(function(){
// data
var newspapers=[{
organization: "The New York Times",
founded: "1851"
},{
organization: "The Washington Post",
founded: "1877"
}];
// pass in the data
$("#container").scrollStory({content: newspapers});
});
Post-instantiation DOM
<div id="container" class="scrollStory scrollStoryActive scrollStoryActiveItem-story0-0">
<div id="story0-0" class="story scrollStoryItem inviewport active" data-organization="The New York Times" data-founded="1851">...</div>
<div id="story0-1" class="story scrollStoryItem" data-organization="The Washington Post" data-founded="1877">...</div>
</div>
Using Data
Item data can be used in most ScrollStory events and callbacks. For example, you can to use the data to dynamically generate markup during instantiation.
$(function(){
var newspapers=[{organization: "The New York Times", founded: "1851"},{organization: "The Washington Post", founded: "1877"}];
$("#container").scrollStory({
content: newspapers,
itembuild: function(ev, item){
item.el.append("<h2>"+item.data.organization+"</h2>");
},
itemfocus: function(ev, item){
console.log(item.data.organization + ", founded in " + item.data.founded + ", is now active!");
}
});
});
Post-instantiation DOM
<div id="container" class="scrollStory scrollStoryActive scrollStoryActiveItem-story0-0">
<div id="story0-0" class="story scrollStoryItem inviewport active" data-organization="The New York Times" data-founded="1851">
<h2>The New York Times</h2>
</div>
<div id="story0-1" class="story scrollStoryItem" data-organization="The Washington Post" data-founded="1877">
<h2>The Washington Post</h2>
</div>
</div>
You could also, for example, manipulate the styles of items as they gain and lose focus. Here we'll interact with the same instanc
Related Skills
node-connect
347.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
