Tutorial : How to add progressive sidebar navigation in Joomla article | Joomla Templates and Extensions Provider

Tips & Tutorials

Joomla Tips & Tutorials

Recently we released our well known Joomla template Purity III in its latest avatar. One of the features in its documentation is that of a progressive sidebar navigation highlighting the progress of scrolling down each section of the page in question. We received few requests regarding this feature and here we are with the details on how you can have one for your own site.

Recommended: It's best to use T3 Framework based templates.
Document navigation with reading progress

Document navigation with reading progress

Let Roll Your Sleeves Up

First, we will create a HTML document with navigation using Bootstrap markup, you can either use Bootstrap 2 or 3:

<div class="doc-container row">
<div class="doc-sidebar col-md-3">
<ul class="doc-nav nav nav-list">
<li><a href="#section-1">Section 1</a></li>
<li><a href="#section-2">Section 2</a></li>
<li><a href="#section-3">Section 3</a></li>
</ul>
</div> 

<div class="doc-content col-md-9">
<section id="section-1">
<h3>Section 1</h3>
<p>Section 1 content here.</p>
...
</section>
<section id="section-2">
<h3>Section 2</h3>
<p>Section 2 content here.</p>
...
</section>
<section id="section-3">
<h3>Section 3</h3>
<p>Section 3 content here.</p>
...
</section>
</div> 
</div>

Then, we add some JavaScript

If you are not familiar with adding JavaScript to T3 framework based templates, please refer to this documentation. The JavaScript that we add to the site will:

  1. Make the navigation stick to the top of the screen when you scroll the documentation,
  2. Activate the document navigation item according to the reading section,
  3. Update reading progress bar.
(function($){

$(document).ready(function(){
var $window = $(window),
        $body = $(document.body),
        $doc = $('.doc-container'),
        $nav = $doc.find ('.doc-nav');

    // make the document navigation affix when scroll
    $nav.affix({
      offset: {
        top: function () {
          return 200; // replace with your top position to start affix
        },
        bottom: function () {
          return 300; // replace your bottom position to release the affix
        }
      }
    });

    // change navigation active according to scroll
    $body.scrollspy({
      target: '.doc-sidebar'
    });   

    // add progress bar for navigation
    $nav.find ('a').before ($('<span class="docs-progress-bar" />'));

    $nav.on ('activate activate.bs.scrollspy', function () {
      $body.scrollspy("refresh");
      var $active = $nav.find('li.active');
      $active.prevAll().find('.docs-progress-bar').css ('width', '100%');
      $active.nextAll().find('.docs-progress-bar').css ('width', '0%');
    });

    $window.on ('scroll', function (event) {
      if (this.timeout) {
        clearTimeout(this.timeout);
      }
      this.timeout = setTimeout (function () {
        var $active = $nav.find('li.active'),
            $progress = $active.find('.docs-progress-bar'),
            $scrollspy = $body.data('bs.scrollspy'),
            scrollTop    = $scrollspy.$scrollElement.scrollTop() + $scrollspy.options.offset,
            scrollHeight = $scrollspy.$scrollElement[0].scrollHeight || $scrollspy.$body[0].scrollHeight,
            maxScroll    = scrollHeight - $scrollspy.$scrollElement.height(),
            offsets      = $scrollspy.offsets,
            targets      = $scrollspy.targets,
            activeTarget = $scrollspy.activeTarget,
            i;

        if (scrollTop >= maxScroll) {
          $progress.css ('width', '100%');
          return ;
        }

        if (activeTarget && scrollTop <= offsets[0]) {
          $progress.css ('width', '0%');
          return ;
        }
        for (i = offsets.length; i--;) {
          if (scrollTop >= offsets[i]
            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])) {
            var p1 = offsets[i],
                p2 = scrollTop,
                p3 = !offsets[i + 1] ? maxScroll : offsets[i + 1],
                p = (p2-p1)/(p3-p1)*100;
            $progress.css ('width', (p < 2 ? 2 : p) + '%');
            return ;
          }
        }
      }, 100);
    });   

});

})(jQuery);

And finish with some simple styling

.doc-nav.affix {
  top: 60px;
}
.doc-nav.affix-bottom {
    position: relative;
}
.doc-nav > li {
    background: none repeat scroll 0 0 #F6F8FA;
    margin-bottom: 1px;
    width: 200px;
}

.doc-nav > li.active > a {
    font-weight: bold;
}

.doc-nav .docs-progress-bar {
    background: none repeat scroll 0 0 #DEE4EC;
    bottom: 0;
    left: 0;
    position: absolute;
    top: 0;
}

Give it a try and let us know if it worked for you. We had love to hear from you on this interesting feature.

BLOG COMMENTS POWERED BY DISQUS