Search code examples
htmlcsshtml-listsreversecss-counter

Reverse the numbering order across multiple OL (not list order)


I'd like to use CSS to obtain an ordered list with continued numbering and in reverse. See attached figure.

enter image description here

Naturally, I'd like the resulting list to be in reverse order, i.e., [5], [4], etc.

Do I have to redesign the CSS part or is it a simple change? I can't figure out how to obtain the reverse numbering.

P.S.: I apologize for not putting the code in the question. Stack Overflow kept saying there was something wrong with it, even though everything was formed correctly in the preview. I lost patience after a few minutes trying to "fix" it.


Solution

  • Using CSS Counters

    Currently there is no way to fully automate reverse numbering across multiple ol elements (without reversing the order of display of list items) with CSS counters when the no. of elements is dynamic. If reversing the order of display of list on the whole is fine, have a look at this answer.

    You can make use of a bit of JavaScript along with counters to achieve this. The approach would be as follows:

    • Using JS, get the count (liCount) of applicable li elements when the page is loaded.
    • Set liCount as the second parameter for the counter-reset property on the parent container which would contain all the applicable ol elements. The second parameter to counter-reset property represents the initial/start value of the counter.
    • In CSS, set -1 as the second parameter for the counter-increment property. Generally the second parameter is the number by which the counter would be incremented every time. Here, since the value is set as -1 the counter would actually get decremented.
    • As normal, display the value of the counter using a :before pseudo element.

    window.onload = function() {
      var liCount = document.querySelectorAll('ol > li').length;
      document.body.setAttribute('style', 'counter-reset: li ' + (liCount + 1));
    }
    ol {
      list-style-type: none;
      margin-left: 20px;
      padding: 0px;
    }
    ol > li {
      counter-increment: li -1;
    }
    ol > li:before {
      content: "[" counter(li) "]";
      padding-right: 10px;
    }
    <div id="content">
      <h3>Year</h3>
      <ul>
        <li><a href="#2010-2015">2010-2015</a></li>
        <li><a href="#2007-2008">2007-2008</a></li>
      </ul>
    </div>
    <h3 id="2010-2015">2010-2015</h3>
    <ol>
      <li>A</li>
      <li>B</li>
      <li>C</li>
    </ol>
    <h3 id="2007-2008">2007-2008</h3>
    <ol>
      <li>D</li>
      <li>E</li>
    </ol>


    Why not reversed attribute?

    • Browser Support for CSS counter is much better than the reversed HTML5 attribute. The reversed attribute is not at all supported by IE and Opera.
    • JS would still be required irrespective of the approach used (to assign counter-reset value for counters, start value for ol reversed) but the JS for setting counter-reset is much simpler than the other when the numbering is across multiple ordered lists.

    Below is a sample snippet using the reversed attribute. I take no credit for the approach as it was taken from the linked thread and other answer here. I have used it with added JS only to illustrate what I meant in Point 2 above.

    window.onload = function() {
      var liCount = document.querySelectorAll('ol > li').length;
      var olEls = document.querySelectorAll('ol[reversed]');
    
      var prevLiCount = 0;
      for (var i = 0; i < olEls.length; i++) {
        /* the below lines are required because start for first ol is from 5 whereas for next is from 2 */
        olEls[i].setAttribute('start', liCount - prevLiCount);
        prevLiCount = olEls[i].querySelectorAll('li').length;
      }
    }
    <div id="content">
      <h3>Year</h3>
      <ul>
        <li><a href="#2010-2015">2010-2015</a>
        </li>
        <li><a href="#2007-2008">2007-2008</a>
        </li>
      </ul>
    </div>
    <h3 id="2010-2015">2010-2015</h3>
    <ol reversed="reversed">
      <li>A</li>
      <li>B</li>
      <li>C</li>
    </ol>
    <h3 id="2007-2008">2007-2008</h3>
    <ol reversed="reversed">
      <li>D</li>
      <li>E</li>
    </ol>