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
Gulp-Sass Fails to Compile SCSS File
Make an Element's Width Relative to Its Height
Webkit Scrollbar CSS, Always a White Box in Corner
Bootstrap 3.0 - Vertically Align 3 Panels in The Same Row (Auto Height)
Z-Index Ie8 Bug on Generated Content with: After
Line Two Divs Side by Side with CSS and React
In Sass, What's The Difference Between The @Mixin and @Extend Directives
Including CSS with '<Link>' or '@Import' - Which Is Better
Text-Decoration: Underline Vs Border-Bottom
How to Have a Border-Bottom on All Except The Last Item
Lato' Font Rendering Odd in Safari, Not in Chrome, or Firefox
Web Safe Font Weights - How to Get Thinner
CSS Width 100% Including Overflow
Incorrect Vertical Alignment in Ie8
Resizing Buttons in Twitter-Bootstrap