Scrolling to infinity
For mortal beings—like me and probably you—there is no such thing as infinity. It's just an abstraction, a symbol for something our bodies can't experience and our minds can't comprehend.
That is, until the dawn of the internet age.
Enter the infinite scroll.
You are probably already familiar with the infinite scroll, and might have even just come from one. In fact, I'm afraid that if I spend too much time explaining what it is, you'll get bored and go back to one.
To help you resist the temptation to switch to an infinitely scrolling app, I've built an infinite scroll into this very page. So if you get bored by me—and I don't blame you—just keep scrolling.
Until then, I'm going to try to explain how an infinite scroll works, and show you how I transformed this very page into an infinite scroll.
What is an infinite scroll?
In case you've been living under a rock, the infinite scroll is an interface that allows you to scroll uninterrupted through an endless stream of content.
OK, maybe not technically endless, but endless for all practical purposes. Most of the apps that employ an infinite scroll have so much potential content that no single person could scroll through it all in one lifetime.
You can find instances of the infinite scroll on the content feeds of popular social media apps, like Instagram, Twitter, and TikTok. There's no refreshing or pagination required to continue imbibing content—you simply graze your finger up across the screen, over and over, until your brain rots or you run out of battery.
So how do these apps manage to transcend the laws of physics?
It's time I let you in on a dirty little secret: they don't. The infinite scroll is not, in fact, infinite. It's just a trick.
One simple trick to achieve infinity
Here's how it works:
You start with a web page of finite length. This page can consist of any digital content: video, text, images, random colors, you name it.
When a user visits this page and scrolls down, they'll eventually get to a point where they've reached the bottom.
At the point—or slightly before it—a function of some sort is triggered that fetches more content for the user. The new content gets appended to the bottom of the page, and the user can now scroll through that content.
When they reach the end of the newly added content, same thing: fetch more content, add it to the bottom of the page, and so on.
That's enough theory. Let's put infinity into practice.
Putting infinity into practice
First we need some content to scroll through.
I'm not a social media company, so I don't have other people's content to use, and I haven't created enough content of my own to populate an infinite feed.
But I do like pretty colors. So how about we scroll through some fun colors for eternity?
This makes implementing the infinite scroll easier since we don't need to fetch data from a database each time the user is close to scrolling to the end. We can just create a new generic HTML element (e.g. a div
), set it's background color to a random color, and append it to the current page.
I'll call these colored HTML elements rectangles, since they'll basically just be colored rectangles roughly the width and height of the user's screen.
At first, we'll start with two of these rectangles on the page.
Then we'll watch—or listen in web development lingo—for when the user gets to the bottom rectangle. At that point we'll add a new rectangle, and then do the same thing over again: watch for when they've scrolled to the new rectangle, and then add another one.
To accomplish this on the web we can use the Intersection Observer API. The Intersection Observer
is browser feature that fires events when elements of a page cross into and out of the viewport, the portion of the page visible on screen. We'll set it to trigger an event when the bottom-most rectangle is visible.
In response to that event, we'll make a new rectangle, append it to the page, and tell the Intersection Observer
to trigger an event when that new rectangle is visible.
We'll keep repeating this process infinitely.
Now let's put it into code.
Putting infinity into code
So we start out with two rectangles in the body of our page's HTML; the rest will be added dynamically with JavaScript as the user scrolls.
We need to use CSS to set the size and color of our HTML rectangles. Here I'm using classes from the CSS library, Tailwind CSS, for shorthand: w-full
sets the width of the rectangle to 100%
while h-screen
sets the height to be 100vh
or 100% of the viewport height. bg-green-300
and bg-blue-600
set green and blue background colors for the starting rectangles.
<body>
<div id="rectangle1" class="w-full h-screen bg-green-300"></div>
<div id="rectangle2" class="w-full h-screen bg-blue-600"></div>
</body>
Next we can set up our Intersection Observer
that will fire events when the bottom rectangle is visible on screen.
We can create it with the Intersection Observer contructor which takes as argument the callback function to be run when an intersection is observed (called here intersectionCallback
).
We add targets to observe by using the observe
method on the Intersection Observer
. The first element we'll want to observe is rectangle2
so I add that to the intersection observer below.
I'm also going to keep track of the number of rectangles on the page in a variable called numRectangles
.
Thus setting up the Intersection Observer
looks like this:
let numRectangles = 2;
let intersectionObserver;
const setupIntersectionObserver = () => {
const options = {
rootMargin: "0px",
threshold: 0,
};
intersectionObserver = new IntersectionObserver(intersectionCallback, options);
const target1 = document.querySelector("#rectangle2");
intersectionObserver.observe(target1);
}
setupIntersectionObserver();
If you run this code, though, you'll get an error telling you intersectionCallback
isn't defined. So let's define this function, which will run when the bottom rectangle is visible.
Inside this function, we'll loop through the elements we're observing for, called "entries". We'll only be observing for one rectangle at a time, so the entries
will be an array of length one. We'll check to see if it isIntersecting
, which means it's at least partially visible on screen. If it is, that means the user is close to the bottom, so it's time to add more "content", which we'll do with another function, addNewContent
.
After adding the new content to the page, we'll "unobserve" that element since we now only care when the next rectangle is visible.
Altogether, that function looks like this:
const intersectionCallback = (entries) => {
entries.forEach((entry)=> {
if (entry.isIntersecting) {
addNewContent();
intersectionObserver.unobserve(entry.target);
}
});
}
Now we need to create the addNewContent
function for adding a new rectangle to the page.
In that function, we'll create a new random rectangle color, and then append a new rectangle, a div
element, to the bottom of the page using the appendChild
method.
We'll set its backgroundColor
style property to be a randomly generated color, and set its width and height to be the dimensionse of the screen (i.e. window.innerWidth
and window.innerHeight
).
Finally, we'll tell the Intersection Obsever
to observe this newly created rectangle.
That function ends up looking like this:
const addNewContent = () => {
numRectangles +=1;
const rectangleColor = 'rgb(' + String(Math.round(255*Math.random())) + ',' + String(Math.round(255*Math.random())) + ',' + String(Math.round(255*Math.random())) + ')';
const newRectangle = document.body.appendChild(document.createElement("div"));
newRectangle.style.backgroundColor = rectangleColor;
newRectangle.style.width = '100%';
newRectangle.style.height = '100vh';
intersectionObserver.observe(newRectangle);
}
And that's all it takes to create an infinitely scrollable page! If you're interested, you can find the code for a basic infinite scroll demo on GitHub.