<main>
	<h1>Infinite Scroll + Pagination Experiment</h1>
	<p>After a poll by <a href="https://twitter.com/smashingmag">@smashingmag</a>, <a href="https://twitter.com/TimSeverien/status/693186708494536704">I got the idea to combine pagination and infinite scroll.</a> The former gives the user control, but needs more effort. The latter lacks control, but requires no special interaction.</p>
	
	<div class="article-list" id="article-list"></div>
	<ul class="article-list__pagination article-list__pagination--inactive" id="article-list-pagination"></ul>
</main>
$animation-duration: .2s;

body {
	background-color: #f8f8f8;
	color: #333;
	counter-reset: page;
	
	-webkit-font-smoothing: antialiased;
	-moz-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
	text-transform: uppercase;
}

a {
	$color: #28f;
	color: $color;
	text-decoration: none;
	
	&:hover, &:focus {
		color: darken($color, 15%);
	}
	&:active {
		color: darken($color, 30%);
	}
}

main {
	margin: 0 auto;
	max-width: 30em;
	padding: 1em;
}

.article-list__page {
	border-top: 1px solid #ddd;
	clear: both;
	counter-increment: page;
	padding-bottom: 3em;
	position: relative;
	
	&:before {
		background-color: #ddd;
		display: inline-block;
		content: counter(page);
		color: #888;
		padding: .25em .5em;
		position: absolute;
		left: calc(50% - .75em);
		top: -.75em;
		vertical-align: middle;
		z-index: 1;
	}
}

.article-list__item {
	background-color: #eee;
	float: left;
	height: 15em;
	max-width: 50%;
	opacity: .75;
	transform: scale(.8);
	transition: opacity $animation-duration, transform $animation-duration;
	width: 15em;
	
	&:hover {
		opacity: 1;
		transform: scale(1);
	}
}

.article-list__item__image {
	display: block;
	height: auto;
	margin: 0;
	opacity: 1;
	transition: opacity $animation-duration;
	width: 100%;
}

.article-list__item__image--loading {
	opacity: 0;
}

.article-list__pagination {
	background-color: #222;
	box-shadow: 0 0 1em rgba(#000, .25);
	display: block;
	bottom: 0;
	left: 0;
	list-style-type: none;
	margin: 0;
	padding: .5em;
	position: fixed;
	right: 0;
	text-align: center;
	transform: translateY(0);
	transition: transform $animation-duration;
	z-index: 2;
}

.article-list__pagination--inactive {
	transform: translateY(100%);
}

.article-list__pagination__item {
	display: inline-block;
	margin: 0 1em;
	
	a {
		$color: #888;
		color: $color;
		text-decoration: none;

		&:hover, &:focus {
			color: lighten($color, 15%);
		}
		&:active {
			color: lighten($color, 30%);
		}
	}
}
View Compiled
function getPageId(n) {
	return 'article-page-' + n;
}

function getDocumentHeight() {
	const body = document.body;
	const html = document.documentElement;
	
	return Math.max(
		body.scrollHeight, body.offsetHeight,
		html.clientHeight, html.scrollHeight, html.offsetHeight
	);
};

function getScrollTop() {
	return (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
}

function getArticleImage() {
	const hash = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
	const image = new Image;
	image.className = 'article-list__item__image article-list__item__image--loading';
	image.src = 'http://api.adorable.io/avatars/250/' + hash;
	
	image.onload = function() {
		image.classList.remove('article-list__item__image--loading');
	};
	
	return image;
}

function getArticle() {
	const articleImage = getArticleImage();
	const article = document.createElement('article');
	article.className = 'article-list__item';
	article.appendChild(articleImage);
	
	return article;
}

function getArticlePage(page, articlesPerPage = 16) {
	const pageElement = document.createElement('div');
	pageElement.id = getPageId(page);
	pageElement.className = 'article-list__page';
	
	while (articlesPerPage--) {
		pageElement.appendChild(getArticle());
	}
	
	return pageElement;
}

function addPaginationPage(page) {
	const pageLink = document.createElement('a');
	pageLink.href = '#' + getPageId(page);
	pageLink.innerHTML = page;
	
	const listItem = document.createElement('li');
	listItem.className = 'article-list__pagination__item';
	listItem.appendChild(pageLink);
	
	articleListPagination.appendChild(listItem);
	
	if (page === 2) {
		articleListPagination.classList.remove('article-list__pagination--inactive');
	}
}

function fetchPage(page) {
	articleList.appendChild(getArticlePage(page));
}

function addPage(page) {
	fetchPage(page);
	addPaginationPage(page);
}

const articleList = document.getElementById('article-list');
const articleListPagination = document.getElementById('article-list-pagination');
let page = 0;

addPage(++page);

window.onscroll = function() {
	if (getScrollTop() < getDocumentHeight() - window.innerHeight) return;
	addPage(++page);
};
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.