3

I have a simple list of li elements that I want to count using the CSS counter() function.

body       {counter-reset: quantity}
ul li      {counter-increment: quantity}
.sum:after {content: counter(quantity)}
<div class="mirror"></div>
<ul>
  <li>..</li>
  <li>..</li>
  <li>..</li>
  <li>..</li>
  <li>..</li>
</ul>
<div class="sum"></div>

The problem is that counter should be at the end of the page (inside the .sum - after all li's it needs to count) but I need to present its value at the top of the page (inside the .mirror or .mirror:after).

I'm trying to find some jQuery solution but nothing works. I'm thinking that the problem is with taking value from the :after pseudo-element.

VXp
  • 11,598
  • 6
  • 31
  • 46
Marcin W
  • 57
  • 7

3 Answers3

1

The problem is that the DOM is read top-to-bottom, with the :after pesudo-elements created on the fly. The elements simply don't exist until they're actually written to the DOM, so a simple change to .mirror:after won't work as you'd expect:

body {
  counter-reset: quantity;
}

ul li {
  counter-increment: quantity;
}

.mirror:after {
  content: counter(quantity);
}
<body>
  <div class="mirror"></div>
  <ul>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
  </ul>
  <div class="sum"></div>
</body>

However, this can be gotten around using JavaScript, and waiting until the page finishes loading before outputting the counter. You can count the elements with document.querySelectorAll. I've gone with a simple li selector for this, but it can easily be more specific if necessary.

To insert them back to the mirror class, you can select it with document.getElementsByClassName, and access it with [0]. The [0] is needed because document.getElementsByClassName returns a NodeList collection of elements, and you want the first result. Then you simply set the content with .innerHTML, as is shown in the following:

var items = document.querySelectorAll('li');
var itemCount = items.length;

var mirror = document.getElementsByClassName('mirror')[0];
mirror.innerHTML = itemCount;
<div class="mirror"></div>

<ul>
  <li>..</li>
  <li>..</li>
  <li>..</li>
  <li>..</li>
  <li>..</li>
</ul>

<div class="sum"></div>

Hope this helps! :)

Obsidian Age
  • 41,205
  • 10
  • 48
  • 71
1

You unfortunately can't access this value through scripts, nor set it to a variable accessible upper in the DOM tree...

What you can do however, is to render your .mirror as if it were upper in the DOM tree, thanks to the flex-direction: column and order CSS3 properties.

.container {
  counter-reset: quantity;
  display: flex;
  flex-direction: column;
}
ul li {
  counter-increment: quantity;
}
.sum:after, .mirror::after {
  content: counter(quantity);
}
/* here swap the display order */
.container > .mirror {
  order: 1;
}
.container > ul {
  order: 2;
}
.container > .sum {
  order: 3;
}
<div class="container">
  <ul>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
  </ul>
  <div class="sum"></div>
  <div class="mirror"></div> <!-- will be moved on top of .container with CSS -->
</div>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
1

You can take advantage of the Flexbox and order property, which comes together with its usage, to display the counter above list items since the .mirror div needs to be placed after the ul element in the DOM:

body {counter-reset: quantity}
ul li {counter-increment: quantity}

.flex-container {
  display: flex; /* assigned flex behavior to the parent wrapper so that you can take advantage of the order property / displays flex-items (children) inline by default, that's why you need to change its direction */
  flex-direction: column; /* now it stacks them vertically */
}

.flex-container > ul {
  order: 1; /* displays list items below the counter even though they are above it in the DOM / 1 because the .mirror div has the default value of 0 */
}

.mirror:after {
  content: counter(quantity);
}
<div class="flex-container">
  <ul>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
    <li>..</li>
  </ul>
  <div class="mirror"></div>
</div>
VXp
  • 11,598
  • 6
  • 31
  • 46