JavaScript: reading progress indicator

JavaScript: reading progress indicator

In this article we're going to implement a reading progress indicator with JavaScript.

In this article we're going to implement a reading progress indicator with JavaScript.

Given the overall height of a content block, an indicator will show the progress of the reading while the user is scrolling the page. The calculation takes into account the viewport's height, the content's height and the current scrolling offset.

The base CSS styles set the indicator at the very top of the page. It's made of an inner bar whose width will change accordingly to the current percentage value obtained from the calculation.

#progress-container {
    position: fixed;
    width: 100%;
    height: 4px;
    left: 0;
    top: 0;
    z-index: 1000;
    background: transparent;
    transition: all ease-out 0.2s;
}

#progress-container.ready {
    transform: translateY(-3px);
}

#progress-bar {
    display: block;
    width: 0;
    height: 3px;
    background: #000;
}

Then we actually need to create the corresponding DOM structure.

const addProgressBar = () => {
    const element = document.createElement('div');
    element.id = 'progress-container';
    element.innerHTML = '<div id="progress-bar"></div>';

    document.body.appendChild(element);
};

Now we can create the main function.

const readingProgress = target => {

    const winTop = window.pageYOffset || document.documentElement.scrollTop;
    const targetBottom = target.offsetTop + target.scrollHeight;
    const windowBottom = winTop + window.outerHeight;
    const progress = 100 - (((targetBottom - windowBottom + window.outerHeight / 3) / (targetBottom - window.outerHeight + window.outerHeight / 3)) * 100);

    document.querySelector('#progress-bar').style.width = progress + '%';

    (progress > 100) ? document.querySelector('#progress-container').classList.add('ready') : document.querySelector('#progress-container').classList.remove('ready');
};

Finally, we can fire everything up when the DOM is ready.

document.addEventListener('DOMContentLoaded', () => {
   const content = document.querySelector('#content');
   addProgressBar();
   readingProgress(content);
   window.addEventListener('scroll', () => {
        readingProgress(content);
   });
});

Demo

JavaScript: reading progress