{"id":169448,"date":"2014-05-07T15:19:44","date_gmt":"2014-05-07T22:19:44","guid":{"rendered":"http:\/\/css-tricks.com\/?p=169448"},"modified":"2020-06-19T08:55:29","modified_gmt":"2020-06-19T15:55:29","slug":"reading-position-indicator","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/reading-position-indicator\/","title":{"rendered":"Reading Position Indicator"},"content":{"rendered":"\n

Lately I’ve seen quite a few websites that have some kind of an indicator to display the current reading position (how much you have “read”, depending on how far you have scrolled down an article). Generally, such indicators are used on blog posts or long form articles and help readers understand how far they are from finishing the article.<\/p>\n\n\n\n\n\n\n\n

Here are some examples:<\/p>\n\n\n\n

\"\"
(View Full Size<\/a>)
1)
Stammy’s blog<\/a> uses a red color progress bar
2)
Ben Frain’s website<\/a> displays the number of words left
3)
Information Architects<\/a> show “minutes left” to indicate the current reading position.<\/figcaption><\/figure>\n\n\n\n

Interestingly, all three techniques represent the same information but with a different approach. I don’t know if there is a name for this feature – so throughout the article, I call it a Reading Position Indicator<\/strong>.<\/p>\n\n\n\n

In this article, we’ll focus on the first technique that uses a horizontal progress bar as the indicator. But instead of using traditional div\/span(s) and some non-linear math to build the indicator, we will use the HTML5 progress element<\/a>. In my opinion is much more semantically accurate and suitable to represent this information, and that too with no complex calculations involved.<\/p>\n\n\n\n

If you have never used the HTML5 progress element before, then I would strongly recommend you to read my article<\/a> on CSS-Tricks that gives you an introduction on how to use this element in your markup and style them via CSS as cross-browser as possible with decent fallback techniques<\/p>\n\n\n

The Problem<\/h3>\n\n\n

To build a reading position indicator, we need to answer two important questions:<\/p>\n\n\n\n

  1. What is the length of the webpage?<\/strong> The length of the webpage is same as the length of the document, which can be calculated via JavaScript.<\/li>
  2. What is the current reading position of the user?<\/strong> Determining the current reading position of the user would entail hacking into the user’s mind to extract the portion of the document currently being read by the user. This appears more like a candidate for Artificial Intelligence and seems impossible; given the scope of technologies that we are dealing with.<\/li><\/ol>\n\n\n\n

    This leaves us with no choice but to tackle this problem statement with a completely different approach.<\/p>\n\n\n

    Principle<\/h3>\n\n\n

    The principle behind this technique is based on a simple fact that the user needs to scroll to reach the end of the web page. Once the user reaches the end of the web page we can conclude that he\/she has finished reading the article. Our technique revolves around the scroll event which is likely to be the key to determine an approximate position of the user while reading.<\/p>\n\n\n\n

    Assuming the user starts reading from the top and will only scroll once he\/she reaches the end of the viewport, we’ll attempt to answer the following questions:<\/p>\n\n\n\n

    1. How much the user needs to scroll to reach the end of the web page?<\/strong> The portion of page that is hidden from the viewport is exactly the amount of scroll the user needs to perform to reach the end of the page. This will become our max<\/code> attribute.<\/li>
    2. How much portion of the page, user has already scrolled?<\/strong> This can be determined by calculating the vertical offset of the top of the document from the top of the window which will become our value<\/code> attribute.<\/li><\/ol>\n\n\n\n
      \"\"
      A demo simulating the scrolling behaviour of the user. As soon as the user starts scrolling in the downward direction to access the hidden part of the web page, the vertical offset increases. Demo on CodePen<\/a><\/figcaption><\/figure>\n\n\n\n

      In the context of the browser, document<\/code> and window<\/code> are two different objects. window<\/code> is the viewable area of the browser (thick blue box in the above example) and document is actually the page that loads inside the window (thin grey box currently scrolling).<\/p>\n\n\n

      Markup<\/h3>\n\n\n

      Let’s start with a basic markup:<\/p>\n\n\n\n

      <progress value=\"0\"><\/progress><\/code><\/pre>\n\n\n\n

      It’s important to explicitly specify the value<\/code> attribute. Otherwise, our progress bar will be in the indeterminate state. We don’t want to add unnecessary styles in CSS for the indeterminate state. Thus we choose to ignore this state by specifying the value attribute. Initially, the user starts reading from the top, hence, the starting value set in the markup is 0<\/code>. The default value of the max<\/code> attribute (if unspecified) is 1<\/code>.<\/p>\n\n\n\n

      To determine the correct value for the max<\/code> attribute, we need to subtract the window’s height from the height of the document. This can only be done via JavaScript, so we will worry about it at a later stage.<\/p>\n\n\n\n

      The placement of the markup in the HTML document would heavily depend on the how rest of the elements are placed. Typically, if you have no fixed position containers in your document, then you can place the progress element right on top of all the elements inside the <\/code> tag.<\/p>\n\n\n\n

      <body>\n  <progress value=\"0\"><\/progress>\n\n  <!--------------------------------\n  Place the rest of your markup here\n  --------------------------------->\n<\/body><\/code><\/pre>\n\n\n

      Styling the indicator<\/h3>\n\n\n

      Since, we want our indicator to always sit on top of the web page, even when the user scrolls, we’ll position the progress element as fixed<\/code>. Additionally, we would want the background of our indicator to be transparent<\/code> so that an empty progress bar doesn’t create a visual hinderance while scrolling through the web page. At the same time this will also help us tackle browsers with JavaScript disabled that we’ll cover later.<\/p>\n\n\n\n

      progress {\n  \/* Positioning *\/\n  position: fixed;\n  left: 0;\n  top: 0;\n\n  \/* Dimensions *\/\n  width: 100%;\n  height: 5px;\n\n  \/* Reset the appearance *\/\n  -webkit-appearance: none;\n     -moz-appearance: none;\n          appearance: none;\n\n  \/* Get rid of the default border in Firefox\/Opera. *\/\n  border: none;\n\n  \/* Progress bar container for Firefox\/IE10+ *\/\n  background-color: transparent;\n\n  \/* Progress bar value for IE10+ *\/\n  color: red;\n}<\/code><\/pre>\n\n\n\n

      For Blink\/Webkit\/Firefox, we need to use vendor specific pseudo elements to style the value inside the progress bar. This will be used to add color to our indicator.<\/p>\n\n\n\n

      progress::-webkit-progress-bar {\n  background-color: transparent;\n}\n\nprogress::-webkit-progress-value {\n  background-color: red;\n}\n\nprogress::-moz-progress-bar {\n  background-color: red;\n}<\/code><\/pre>\n\n\n

      Interaction<\/h3>\n\n\n

      Calculating the width\/height of window and document in JavaScript is messy and varies horribly across different breed of browsers<\/a>. Thankfully, jQuery manages to abstract all the complexities offered by these browsers and provides a much cleaner mechanism to calculate the dimensions of window and document. Hence, for the rest of the article we’ll rely on jQuery to handle all our interactions with the user.<\/p>\n\n\n\n

      Before, we begin, do not forget to add jQuery library to your document.<\/p>\n\n\n\n

      <script src=\"\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.11.0\/jquery.min.js\"><\/script><\/code><\/pre>\n\n\n\n

      We need jQuery to determine the max<\/code> and the value<\/code> attribute of our progress element.<\/p>\n\n\n\n