
Infinite featured-post scroll with Publii static site generator
The majority of people who use the internet (or just people - everyone uses the internet) can be divided into two camp: people who plug a search query into Google, then either visit a page or digest the AI summary, and doomscrollers.
Doomscrolling is the modern curse of mankind, and can lead to teenagers wasting their lives flicking from video to video on TikTok, YouTube shorts, Instagram Reels, and SnapChat.
This is especially galling during what promises to be a record breaking summer in the UK, and from the garden, The Crow can hear the occasional snicker through the teen's bedroom window, as yet another perfectly timed 60-second prank fails successfully.
The other type of visitor isn't ideal either. While we delight in each and every visit to The Crow, it's slightly irritating that people just smash and grab. It would be nice if guests hung around a bit longer, Maybe they'd click through a sponsored link to purchase a very reasonably priced domain name or perhaps buy us a coffee. It's feasible that they could discover an article they weren't looking for, and share it with a friend.
An Infinite Scroll to scroll infinitely
We created this website with Publii and it's hosted on GItHub Pages. Publii themes already have the option of having all posts displayed on the site homepage - and who spends any time on the homepage anyway? The behaviour we wanted was as follows:
The reader scrolls to the bottom of a post page.
A new article appears in-line and without fuss.
The URL in the browser URL bar changes to reflect the new article.
The page title changes to reflect the new article title.
The view is logged by our self-hosted Matomo analytics server with the correct URL and article title
There are a couple of things to note about this spec list:
The articles should be of interest generally. Not everything published on The Crow is solid gold, and posts detailing how to install Golang are really helper pieces for different articles.
We want Matomo to track visits because we want to see how well this is working. We're not stalking you across the interwebs and selling your data to the highest bidder. This is purely internal.
Publii has a "Featured" feature which allows us to flag articles we want to appear in the side bar to be clicked. They're pieces we're particularly pleased with and provide a great source for our infinite scroll feature.
Infinite scroll isn't a new feature on static sites
From what we were able to glean during a quick search of Publii's own GitHub Discussion forum, Infinite Scroll is definitely a thing on Publii, and the Premium (paid) version of the Persona theme already has it. But we're pretty invested in our customised TechNews theme right now, and besides, there's a ready-made solution out there in the form of the venerable and much-loved Infinite-scroll.
The script has plenty of options, but none of them quite did what we needed. New requirements appeared in our spec list which resulting in us hacking on the code until it did what we damned well wanted.
Essentially, our modded script grabs the URLs from the featured column and creates a new array - starting with the current article - whether featured or not - and progresses through the featured posts in date order from the top.
When the reader approaches the bottom of the post, the next post is loaded from the array. The page title and URL bar update, and Matomo grabs the new page view.
A modified Infinite Scroll script for Publii
After some heavy (and probably largely unnecessary) butchery this is what we came up with. We admit it's unlikely to be the most elegant solution.
<script src="https://unpkg.com/infinite-scroll@5/dist/infinite-scroll.pkgd.min.js"></script>
<script>
const postContainer = document.querySelector('.content');
const currentUrl = window.location.href.split('#')[0];
const featuredLinks = [...document.querySelectorAll('.featured__container a')]
.map(a => a.href.split('#')[0]);
const combinedLinks = [currentUrl, ...featuredLinks];
const postLinks = [...new Set(combinedLinks)];
let currentIndex = 0;
if (postContainer && postLinks.length > 1) {
const infScroll = new InfiniteScroll(postContainer, {
path() {
const nextIndex = currentIndex + 1;
return postLinks[nextIndex] || null;
},
append: '.content',
history: false,
scrollThreshold: 400,
responseType: 'document',
});
infScroll.on('load', () => {
currentIndex++;
});
infScroll.on('load', (response) => {
const newTitle = response?.querySelector('title')?.innerText;
if (newTitle) {
document.title = newTitle;
}
});
infScroll.on('append', (body, path) => {
if (path) {
window.history.pushState({}, '', path);
if (window._paq) {
window._paq.push(['setCustomUrl', path]);
window._paq.push(['setDocumentTitle', document.title]);
window._paq.push(['trackPageView']);
}
}
});
}
window.addEventListener('popstate', () => {
window.location.reload();
});
</script>
It works - or at least it seems too, although we're forced to admit that it took far longer than it should have.
To improve the experience for readers, we decided to remove the author bio, post navigation, and related posts from the bottom of all posts. If you're that interested in this writer, you can click my name next to the date, and honestly, the "related posts" feature never worked that well for us anyway. One other thing to note is that lazy loading images borked things for us. YMMV.
Are we happy with how The Crow looks and feels now?
Well, we're not unhappy with it. Publii gets the job done with less fuss and tinkering than does Jekyll, and GitHub integration make it a neat publishing solution. On the other hand, the site is fairly hefty. We'll work on that in the future.
There are a few features we integrated into our Jekyll / Raspberry Pi workflow which we'd like to bring back, such as our janky log-based commenting system.
For now though, scrolling through featured posts is pretty natty. And yes, we know it's not actually infinite.