How to Get The CSS Counter Value of The Parent

Can I get the CSS counter value of the parent?

You use two different counters: one for the li parents and one for the li subitems. Then, in each li subitem, concatenate multiple counter() functions using each counter, like this:

ol {
counter-reset: item;
}

ol ol {
counter-reset: subitem;
}

li {
display: block;
}

/* First level of parent items */
li:before {
content: counter(item, decimal-leading-zero) ' ';
counter-increment: item;
}

/* Second level of subitems */
li li:before {
/* counter(item) for the parents, counter(subitem) for the subitems */
content: counter(item, decimal-leading-zero) counter(subitem, lower-alpha) ' ';
counter-increment: subitem;
}

jsFiddle demo, tested in all browsers that support :before and CSS2.1 counters including IE8+

Useful reading: W3C CSS2.1 generated content spec, §12.4.1 Nested counters and scope

counter-increment on parent, but content on child

Update: I saw the MDN example that you probably used for inspiration in creating this. The confusing part of translating that into your markup is that they use <ol> and <li> tags which encompass child elements. This doesn't make as much sense in the context of header <h_> elements, but it seems you have to keep the child elements within them to accomplish the same thing. I added the after elements and some light css to show where each element ends. Hope this helps.

.section {  counter-reset: section;                /* Creates a new instance of the                                            section counter with each ol                                            element */  list-style-type: none;}
.header::before { counter-increment: section; /* Increments only this instance of the section counter */ content: counters(section, ".") " "; /* Combines the values of all instances of the section counter, separated by a period */}
.section{ font-size: 16px; margin: 10px 0;}h1::after { content: ' (end h1)';}
h2 { margin-left: 10px;}h2::after { content: ' (end h2)';}
h3 { margin-left: 20px;}h3::after { content: ' (end h3)';}
<div id="root">  <div class="section">    <h1 class="header">item</h1>          <!-- 1     -->    <h1 class="header">item               <!-- 2     -->      <div class="section">        <h2 class="header">item</h2>      <!-- 2.1   -->        <h2 class="header">item</h2>      <!-- 2.2   -->        <h2 class="header">item           <!-- 2.3   -->          <div class="section">            <h3 class="header">item</h3>  <!-- 2.3.1 -->            <h3 class="header">item</h3>  <!-- 2.3.2 -->          </div>         </h2>         <h2 class="header">item           <div class="section">            <h3 class="header">item</h3>  <!-- 2.4.1 -->            <h3 class="header">item</h3>  <!-- 2.4.2 -->            <h3 class="header">item</h3>  <!-- 2.4.3 -->          </div>        </h2>        <h2 class="header">item</h2>      <!-- 2.5   -->      </div>    </h1>    <h1 class="header">item</h1>          <!-- 3     -->    <h1 class="header">item</h1>          <!-- 4     -->  </div></div>

How can I read the applied CSS-counter value?

None that I can think of, no. :before pseudo-elements are not part of the DOM so there is no way to address their content.

You could make a function that scanned the stylesheet's DOM for the :before rules and worked out which rules the browser had applied where, but it would be incredibly messy.

Ordered list CSS style includes parent number

You should use CSS counters W3C specs (as @Zeta) has pointed out, but here is an approach that will handle multiple nesting and latin counters ..

ol{
list-style: none;
}
ol.roman{
counter-reset: roman;
}
ol.roman > li:before{
counter-increment: roman;
content: counter(roman, upper-latin)".";
padding-right:5px;
}
ol.roman li ol{
counter-reset: inner;
}
ol.roman ol li:before{
counter-increment: inner;
content: counter(roman, upper-latin)"."counters(inner,'.');
padding-right:5px;
}

Demo at http://jsfiddle.net/gaby/nZQSF/

Ordered List with Parented Value

I ended up writing some JavaScript to generate a stylesheet with unique classes for each LI to set the value.

var lists = document.getElementsByClassName('parented');for(var i = 0; i < lists.length; i++) {  var test = lists[i].getElementsByTagName('li'), parent = [], cparent = 0, j = 0;  for(var k = 0; k < test.length; k++) {    if((test[k].getElementsByTagName('ol').length + test[k].getElementsByTagName('ul').length) != 0) {      parent.push(test[k]);      k++;    }  }  var style = document.createElement('style');  style.id = 'parented';  document.head.appendChild(style);  style = document.getElementById('parented');  for(var k = 0; k < parent.length; k++) {console.log(cparent);    var pnum = (parent[k].hasAttribute('value') ? parent[k].getAttribute('value') : (parseInt((k < cparent) ? cparent : k) + 1));    cparent = pnum;    var child = parent[k].getElementsByTagName('li'), rule = 'parent' + (i + 1) + pnum, content = pnum;    style.innerHTML = style.innerHTML + '.' + rule + '::before { content: "' + content + '."; }';    parent[k].className = rule;    for(var l = 0; l < child.length; l++) {      rule = 'parent' + (i + 1) + pnum + (l + 1);      content = pnum + '.' + (l + 1);      style.innerHTML = style.innerHTML + '.' + rule + '::before { content: "' + content + '"; }';      child[l].className = rule;    }  }}
ol.parented {  margin-left: .6875em !important;}ol.parented, .parented ol {  list-style: none !important;}ol.parented > li:before, ol.parented ol li:before {  padding-right: 9px;}
<ol class="parented">  <li>Value 1<ol>    <li>Value 1.1</li>    <li>Value 1.2</li>    <li>Value 1.3</li>  </ol></li>  <li value="4">Value 4<ol>    <li>Value 4.1</li>    <li>Value 4.2</li>    <li>Value 4.3</li>  </ol></li>  <li>Value 5<ol>    <li>Value 5.1</li>    <li>Value 5.2</li>    <li>Value 5.3</li>  </ol></li>  <li>Value 6<ol>    <li>Value 6.1</li>    <li>Value 6.2</li>    <li>Value 6.3</li>  </ol></li>  <li value="10">Value 10<ol>    <li>Value 10.1</li>    <li>Value 10.2</li>    <li>Value 10.3</li>  </ol></li></ol>

How to use css counters in nested lists without parent index while not using a separate counter for each level

Looks funny, but you might use counter() not counters():

.list {
counter-reset: section;
}

.item::before {
counter-increment: section;
content: counter(section) '. ';
}

.list .list .item {
margin-left: 30px;
}
<div class='list'>
<div class='item'>item</div>
<div class='item'>item
<div class='list'>
<div class='item'>item</div>
<div class='item'>item
<div class='list'>
<div class='item'>item</div>
<div class='item'>item</div>
<div class='item'>item </div>

</div>
</div>
<div class='item'>item </div>

</div>
</div>
<div class='item'>item</div>
<div class='item'>item</div>
</div>

Pass counter component value to it's parent component

Unlike with classes, React doesn't have a callback as a second arg on the setter. So you could call the handler inside the setter callbacks though technically the state hasn't changed yet:

const decrementHandler = () => {
setNumber((prevState) => {
if (prevState === 0) {
return 0
}
props.onCounterChange(prevState - 1);
return prevState - 1;
})
}

const incrementHandler = () => {
setNumber((prevState) => {
props.onCounterChange(prevState + 1);
return prevState + 1;
})
}

Or you could call it after the state has changed with a useEffect, note this will be called when the component inits with 0 too:

useEffect(() => {
props.onCounterChange(number);
}, [number])

Careful not to get a stale reference but make sure onCounterChange is constant too (useCallback):

useEffect(() => {
props.onCounterChange(number);
}, [props.onCounterChange, number])

Or tunnel the callback in, ugly but doesn't depend on the user creating a constant reference to onCounterChange (arrow functions are new every time):

const onCounterChangeRef = useRef(props.onCounterChange);
onCounterChangeRef.current = props.onCounterChange

useEffect(() => {
onCounterChangeRef.current(number);
}, [number])

Use css counter in calc

The Question Can I use the counter(skill) inside a calc()

No. You can't.

The calc function does not permit the use of counter functions as its components. From the specs here - https://www.w3.org/TR/css3-values/#calc-notation:

Components of a
calc() expression
can be literal values or
attr() or
calc()
expressions.

There have been many requests for this but always declined. The underlying reason seems to be that the counter() function represents (outputs) a <string> and hence cannot be used directly in calc. Moreover, the counters are considered very expensive for the browsers.

Reference: https://lists.w3.org/Archives/Public/www-style/2016Aug/0082.html

However, there have been proposals for adding a counter-value() function which would return the value as integer and could be used in calc. See here: https://drafts.csswg.org/css-lists-3/#counter-functions (Scroll down to see Issue 4).

So as of now, you cannot use counter inside of calc and the counter-value does not exist yet.



Related Topics



Leave a reply



Submit