This is where CSS shines in comparison to plain markup language transitions to HTML. The CSS counter function is flexible and rich in language and predefined symbols. All done for you. No need to do it programatically.
Your short on this saved me so much time last week. I’m showing progress on an employment application process that has different steps depending on the particular job and individual items can be completed out of order. Using this and the :has and :not, was able to put in the numbered steps and swap out the number for a check mark if the item has a completed tag.
It is a pity that I can not like video more than once) I liked video after watching it only for 3 minutes and were going to like it again then I remembered that I had already done this. I used to copy/paste when I wanted customise my counter but now I understand what I have been doing and now it makes perfect sence! TY!
For accessibility, if you use the ol>li structure it should do the trick; it's how I've been using it on projects. The one hiccup I ran into is that I can't change the display from list-item without breaking the native counter handling ([reversed] and [start] attributes in particular), which is hard to fully recreate. Not like it gets used much though.
I run into this a few days and I ended up putting the content inside a span (block), but it will depend on the use case really, I just needed to truncate the texts without breaking the list-item.
Oh the content prop ❤ would be neat to see you go over @counter-style ; its now Baseline support! Provides so many possibilites! The "prefix" and "pad" properties give an alternative for the use case 'decinal leading zero'. Also a comparison to :marker and when to use which!! And counter-set vs counter-reset; whats the difference ? Love to see the content back to illuminating the world of css!! Great work KPow!!! You should introduce yourself as KaPow!! 😆
5:20 For anyone how may be thinking how to do it in JS, I'd go with ".padStart(2, 0)" This function will increase the size of your string until it hits the length of the first param, and to do so it will add the second param at the beginning just as needed If your string happens to have length bigger or equals the first param, it does nothing
Glad you showed 10 for the increment, since decimal-leading-zero I think has a bug. It should be leading to max place of the decimal. What happens: 10, 20, ..., 80, 90, 100, 110 Expected: 010, 020, ..., 080, 090, 100, 110
I agree I just know I have had to write JS a few times to have leading 0's to the digits to the left of the decimal more than twice and not talking about for dateTime.
What's going to happen if you flip your flex direction? What I'm asking is are counters numbered as per the markup order? Or are they numbered as per the final layout? You would hope and think it would be the latter. So in your example if you reverse the flex direction it should effectively go from 10 down to 1
Counters are really useful, however, they would be even more useful if we could use them in calculations. I hope that is possible one day. A small detail - you mentioned that the counter-increment needs to be on one of the parents but it can also be on the pseudo element itself.
yeah, be *really* nice if we could use them for more things. I think there is some stuff in the works there. And yeah, good catch on the increment. I had it in my mind that the first one would have been 0, and it would have incremented after, but you're right :)
Thank you for this and all your other excellent videos. But maybe, a video about CSS counters should also mention the CSS function "counters()". It can be used for structured numbering across several hierarchy levels. In spite of not being a typical requirement for web pages I use it in markdown, especially for automatically generated TOCs, which usually transpile to html markup based on and . //// /// Nested ordered lists are enriched by structured list numbers /// 1. 1st level, 1st item /// 1.1 2nd Level 1st item /// 1.2 2nd Level, 2nd item /// 2. 1st level, 2nd item /// /// There seems to be a bug or undocumented feature concerning /// the implicit counter "list-item" which is incremented also inside /// unordered lists. To prevent that, I use my own explicit counter. //// /// reset the counter instance for each ordered list /// and increment it for direct list item children ol { counter-reset: my-list-item; > li { counter-increment: my-list-item; } } /// There is a trailing dot (.) at the top level but not at the lower levels ol { > li::marker { content: counters(my-list-item, ".") quote(". "); } ol > li::marker { content: counters(my-list-item, ".") quote(" "); } } Inside the markdown file you have to include the style: For achieving coincidence between the ordered list of the TOC and the headers, I use the following sass code: //// /// This SCCS file provides the CSS rules for adding structured numbers to /// the HTML header elements ,..., /// @author: Dr. Wolfgang Backes (wolfgangbackes@dr-backes-it.de) //// // The number of header levels to deal with $max_header: 6; @each $i, $size in (1: 2, 2: 1.8, 3: 1.8, 4: 1.5, 5: 1.2, 6: 1) { h#{$i} { font-size: $size + em; } } /// function nested_number /// @access private /// @param {Number} $i - Current nesting level /// @return {String} - A string representing the hierarchical numbering /// @example scss - Using the numbering function /// h2::before { /// content: numbering(2); /// // Assuming the counters for levels 1 and 2 are 4 and 1, outputs `4.1` /// } @function nested_number($i) { @if $i == 2 { @return counter(h2) quote("."); } $n: counter(h2); @for $j from 3 through $i { $n: $n quote(".") counter(h#{$j}); } @return $n; } /// Each heading level has a counter of the same name. Whenever a new heading /// of a certain level is encountered, the counter for the next level is reset. /// The top level header, namely h1 never needs being reset. /// The content of the pseudo-element is determined by means of the function /// 'nested_number' and adding a space character for separating the number /// from the header text. /// @example scss - Using the structured numbering /// h2 { /// counter-reset: h3; /// &::before { /// counter-increment: h2; /// content: nested_number(2) " "; /// } /// } @for $i from 2 through $max_header { h#{$i} { counter-increment: h#{$i};
I could definitely do a follow-up there, and that's a great use case for counters(). I was trying to keep things relatively short. I was already moving pretty fast over a few of the things I looked at I think!
Does your CSS Demystifying course get updates regularly? I am planning to buy it. Doesn't it include Flexbox mastery which I am seeing as a separate course?
Amazing power of CSS! As an alternative, could you style the number of an OL rather than adding a number to a UL? And a follow up question, by adding a number to a UL, does this semantically make it an OL for screenreaders?
Yeah, just using an OL and styling the ::marker pseudo-element might be better given this HTML, although 'markers' only allow a few CSS properties. I've used 'counter' in other places, where the markup isn't directly a numbered list , e.g. a DL, to number the DT + DD children in pairs.
BBC News homepage uses a list decorated with numbers for their "Most watched" and "Most read" sections very similar to Kevin's example - I notice their html uses an OL for these sections with numbers, and UL for the other sections without numbers - but no CSS magic, just hardcoded numbers in a DIV!
i was wondering, if you made the first example using an OL, would a screen reader read the number twice? (once for the implicit OL one, and once for the one you added with counter…?)
Using an is for something where the numbering is important, rather than decorational, which I saw it as here. For example, the steps in a recipe that you're making. Granted, if you need better styling options for your this could come in handy as well
I keep getting 0 for a counter that's supposed to increment within a certain .class, instead of the expected value of 25. The document is dynamically-generated by JS, but shouldn't the counters set up in CSS still work??
It uses the dom order. Visual order, as of right now, has no influence on *anything* other than what we see on the page, though there is some converstations going on that might give us some options there.
@@KevinPowell Thank you for the reply. I guess for hidden items you could hide them with a class (e.g hide-me) and your selector that increments could include :not(.hide-me)...
@@NotKyleChicago I just tested (in FF) and we're both wrong, it seems any item hidden with display: none; doesn't increment the counter no matter how the increment is applied. In other words there's no need to use :not(.hide-me) on the increment class as I suggested above, e.g: .hide-me { display: none; } .cards { counter-reset: card-counter; } .cards > .card { counter-increment: card-counter; } .cards > .card::after { content: counter(card-counter); } Card 1, Counter Card 2, Counter Card 3, Counter Card 4, Counter Card 5, Counter Card 6, Counter Results in: Card 1, Counter 1 Card 3, Counter 2 Card 5, Counter 3 Card 6, Counter 4
Can CSS counters be used to dynamically add numbers as suffixes to classes, for example, if i had a bunhc of accordions which i want to open and close independently, for which i need to have uniqe IDs or class-counters.
This is where CSS shines in comparison to plain markup language transitions to HTML.
The CSS counter function is flexible and rich in language and predefined symbols.
All done for you. No need to do it programatically.
I could see this being useful for the axis values on graphs, for example.
I am a back end developer and you have rekindled my interest in css! Thanks
Your short on this saved me so much time last week. I’m showing progress on an employment application process that has different steps depending on the particular job and individual items can be completed out of order.
Using this and the :has and :not, was able to put in the numbered steps and swap out the number for a check mark if the item has a completed tag.
Just used it recently on a project I'm working on. Nice amd simple!
I've been using this for a few years now for the headings for my rules and the privacy policy on my website. Very convenient.
It is a pity that I can not like video more than once) I liked video after watching it only for 3 minutes and were going to like it again then I remembered that I had already done this. I used to copy/paste when I wanted customise my counter but now I understand what I have been doing and now it makes perfect sence! TY!
Thanks Kevin, really useful to know, and I can see it been used over and over.
Simple when see it explained like this, but would never have known.
Using "counter" as counter is counterintuitive :P
Nice one!
Im never gonna forget this and i hate it lol
For accessibility, if you use the ol>li structure it should do the trick; it's how I've been using it on projects.
The one hiccup I ran into is that I can't change the display from list-item without breaking the native counter handling ([reversed] and [start] attributes in particular), which is hard to fully recreate. Not like it gets used much though.
I run into this a few days and I ended up putting the content inside a span (block), but it will depend on the use case really, I just needed to truncate the texts without breaking the list-item.
Oh the content prop ❤ would be neat to see you go over @counter-style ; its now Baseline support! Provides so many possibilites! The "prefix" and "pad" properties give an alternative for the use case 'decinal leading zero'.
Also a comparison to :marker and when to use which!!
And counter-set vs counter-reset; whats the difference ?
Love to see the content back to illuminating the world of css!! Great work KPow!!! You should introduce yourself as KaPow!! 😆
5:20 For anyone how may be thinking how to do it in JS, I'd go with ".padStart(2, 0)"
This function will increase the size of your string until it hits the length of the first param, and to do so it will add the second param at the beginning just as needed
If your string happens to have length bigger or equals the first param, it does nothing
Glad you showed 10 for the increment, since decimal-leading-zero I think has a bug. It should be leading to max place of the decimal.
What happens: 10, 20, ..., 80, 90, 100, 110
Expected: 010, 020, ..., 080, 090, 100, 110
i dont think its "expected"
I agree I just know I have had to write JS a few times to have leading 0's to the digits to the left of the decimal more than twice and not talking about for dateTime.
Wow! This came at the exact moment I needed something like this -- thanks!
What's going to happen if you flip your flex direction? What I'm asking is are counters numbered as per the markup order? Or are they numbered as per the final layout? You would hope and think it would be the latter. So in your example if you reverse the flex direction it should effectively go from 10 down to 1
Counters are really useful, however, they would be even more useful if we could use them in calculations. I hope that is possible one day.
A small detail - you mentioned that the counter-increment needs to be on one of the parents but it can also be on the pseudo element itself.
yeah, be *really* nice if we could use them for more things. I think there is some stuff in the works there. And yeah, good catch on the increment. I had it in my mind that the first one would have been 0, and it would have incremented after, but you're right :)
Thank you for this and all your other excellent videos. But maybe, a video about CSS counters should also mention the CSS function "counters()". It can be used for structured numbering across several hierarchy levels. In spite of not being a typical requirement for web pages I use it in markdown, especially for automatically generated TOCs, which usually transpile to html markup based on and .
////
/// Nested ordered lists are enriched by structured list numbers
/// 1. 1st level, 1st item
/// 1.1 2nd Level 1st item
/// 1.2 2nd Level, 2nd item
/// 2. 1st level, 2nd item
///
/// There seems to be a bug or undocumented feature concerning
/// the implicit counter "list-item" which is incremented also inside
/// unordered lists. To prevent that, I use my own explicit counter.
////
/// reset the counter instance for each ordered list
/// and increment it for direct list item children
ol {
counter-reset: my-list-item;
> li {
counter-increment: my-list-item;
}
}
/// There is a trailing dot (.) at the top level but not at the lower levels
ol {
> li::marker {
content: counters(my-list-item, ".") quote(". ");
}
ol > li::marker {
content: counters(my-list-item, ".") quote(" ");
}
}
Inside the markdown file you have to include the style:
For achieving coincidence between the ordered list of the TOC and the headers, I use the following sass code:
////
/// This SCCS file provides the CSS rules for adding structured numbers to
/// the HTML header elements ,...,
/// @author: Dr. Wolfgang Backes (wolfgangbackes@dr-backes-it.de)
////
// The number of header levels to deal with
$max_header: 6;
@each $i, $size in (1: 2, 2: 1.8, 3: 1.8, 4: 1.5, 5: 1.2, 6: 1) {
h#{$i} {
font-size: $size + em;
}
}
/// function nested_number
/// @access private
/// @param {Number} $i - Current nesting level
/// @return {String} - A string representing the hierarchical numbering
/// @example scss - Using the numbering function
/// h2::before {
/// content: numbering(2);
/// // Assuming the counters for levels 1 and 2 are 4 and 1, outputs `4.1`
/// }
@function nested_number($i) {
@if $i == 2 {
@return counter(h2) quote(".");
}
$n: counter(h2);
@for $j from 3 through $i {
$n: $n quote(".") counter(h#{$j});
}
@return $n;
}
/// Each heading level has a counter of the same name. Whenever a new heading
/// of a certain level is encountered, the counter for the next level is reset.
/// The top level header, namely h1 never needs being reset.
/// The content of the pseudo-element is determined by means of the function
/// 'nested_number' and adding a space character for separating the number
/// from the header text.
/// @example scss - Using the structured numbering
/// h2 {
/// counter-reset: h3;
/// &::before {
/// counter-increment: h2;
/// content: nested_number(2) " ";
/// }
/// }
@for $i from 2 through $max_header {
h#{$i} {
counter-increment: h#{$i};
@if $i < $max_header {
counter-reset: h#{$i + 1};
}
&::before {
content: nested_number($i) quote(" ");
}
/// headers without incrementing and without numbering
&.clsNoNumbering {
counter-increment: none;
&::before {
content: "";
}
}
}
}
I could definitely do a follow-up there, and that's a great use case for counters(). I was trying to keep things relatively short. I was already moving pretty fast over a few of the things I looked at I think!
Thanx for your dedication to CSS.
In my opinion JS has the way more flexibility and usability.
Wow this is so cool!
You mentioned JavaScript so JS has a built in function called padStart and conversely padEnd which adds leading or trailing characters
It would be nice to be able to refer to an item by the counter value. Like saying "See paragraph 3" to refer to the paragraph where the counter is 3.
As always a great video!! 👍👍👍
wow cool!
Do css counters offer an easy ‘count’ of counted elements? Like if I wanted a ‘1 of 8’, ‘2 of 8’, … ‘8 of 8’ pattern?
Does your CSS Demystifying course get updates regularly? I am planning to buy it. Doesn't it include Flexbox mastery which I am seeing as a separate course?
This is so nice
you are the best!
Can counters, or OL/LI for that matter, be leveraged as unique attribute generators?
And what about conditional styling based on counter? For example style 10th header red :)
Amazing power of CSS!
As an alternative, could you style the number of an OL rather than adding a number to a UL?
And a follow up question, by adding a number to a UL, does this semantically make it an OL for screenreaders?
Yeah, just using an OL and styling the ::marker pseudo-element might be better given this HTML, although 'markers' only allow a few CSS properties.
I've used 'counter' in other places, where the markup isn't directly a numbered list , e.g. a DL, to number the DT + DD children in pairs.
BBC News homepage uses a list decorated with numbers for their "Most watched" and "Most read" sections very similar to Kevin's example - I notice their html uses an OL for these sections with numbers, and UL for the other sections without numbers - but no CSS magic, just hardcoded numbers in a DIV!
i was wondering, if you made the first example using an OL, would a screen reader read the number twice? (once for the implicit OL one, and once for the one you added with counter…?)
Using an is for something where the numbering is important, rather than decorational, which I saw it as here. For example, the steps in a recipe that you're making.
Granted, if you need better styling options for your this could come in handy as well
As always, great video pal! Can you do an "advanced animations and micro interactions" series?
I was waiting to hear "AND THE BROWSER SUPPORT FOR THIS..." Lol
Great video as always.
You can use it in IE8 if you want, so I didn't bother mentioning it, lol
Rather than displaying the counter number, can it be placed in a data attribute? I'mma find out
The decimal-leading-zero doesn’t add an extra zero when you hit 100? 6:57
Then you would just use 10 :)
is it supposed to?
Does it support 2 leading 0s? Like 001 to 999?
What's the browser support for this?
I keep getting 0 for a counter that's supposed to increment within a certain .class, instead of the expected value of 25. The document is dynamically-generated by JS, but shouldn't the counters set up in CSS still work??
Having an order on an UNordered list feels weird. Useful tip, though. Thanks!
CSS 선생님
Hi, can you please do a video on mixins 🎉
I can't get this to work in Safari?
How does this interact with order? Does it use the DOM order or the visual layout order if I re-order items or hide them with display: none;?
It uses the dom order. Visual order, as of right now, has no influence on *anything* other than what we see on the page, though there is some converstations going on that might give us some options there.
@@KevinPowell Thank you for the reply. I guess for hidden items you could hide them with a class (e.g hide-me) and your selector that increments could include :not(.hide-me)...
@@KevinPowell So, if an item has display: none, the counter would appear to skip a number?
@@NotKyleChicago I just tested (in FF) and we're both wrong, it seems any item hidden with display: none; doesn't increment the counter no matter how the increment is applied. In other words there's no need to use :not(.hide-me) on the increment class as I suggested above, e.g:
.hide-me {
display: none;
}
.cards {
counter-reset: card-counter;
}
.cards > .card {
counter-increment: card-counter;
}
.cards > .card::after {
content: counter(card-counter);
}
Card 1, Counter
Card 2, Counter
Card 3, Counter
Card 4, Counter
Card 5, Counter
Card 6, Counter
Results in:
Card 1, Counter 1
Card 3, Counter 2
Card 5, Counter 3
Card 6, Counter 4
@@NotKyleChicago If you did want to skip a card you could do it like this:
.cards {
counter-reset: card-counter;
}
.cards > .card:not(.skip-me) {
counter-increment: card-counter;
}
.cards > .card:not(.skip-me)::after {
content: ', Counter ' counter(card-counter);
}
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
Results in:
Card 1, Counter 1
Card 2
Card 3, Counter 2
Card 4, Counter 3
Card 5, Counter 4
Card 6, Counter 5
It's unfortunate that I can't use it to modify other integer properties.
--_offset-size could be remove in the example below:
:where(*, *::before, *::after) {
padding: 0px;
margin: 0px;
box-sizing: border-box;
font: inherit;
}
.wrapper {
position: relative;
isolation: isolate;
input {
appearance: none;
background-color: black;
color: white;
display: grid;
transition: top 0.3s;
padding: 0.125rem;
&::before {
content: attr(data-value);
}
&:checked {
font-size: 1.5rem;
&::after {
font-size: 1rem;
content: attr(value);
}
}
&:not(:checked) {
position: absolute;
inset: 0px 0px auto 0px;
z-index: -1;
}
&:checked~input {
--_offset-balance: 1;
}
}
&:focus-within:not(:has(input:checked:focus)) {
input:not(:checked) {
top: 100%;
transform: translateY(calc(100% * (var(--_offset-size) - var(--_offset-balance, 0))));
}
}
&:is(:not(:focus), :has(input:checked:focus))::after {
content: "";
position: absolute;
inset: 0px;
}
}
yeah, that would be great
Would it be possible to use counter to delay animations?
Good question... I don't think so 🤔 - we do have some css counting stuff that's in the works that might be able to...
Can CSS counters be used to dynamically add numbers as suffixes to classes, for example, if i had a bunhc of accordions which i want to open and close independently, for which i need to have uniqe IDs or class-counters.
No, it only adds numbers as content
using same exact name for different variables is not confusing at all for an example people are meant to learn from........
keeewl...
Hm. Countervalues are more content than styles. So a new html-tag would be a more intuitive solution.
Where’s my “css is not a programming language” bros?
Can I do leading zeros with Roman numerals? Now that would be interesting. 😁
Why doesn't anyone think of the children!