Use css counter in calc
Asked Answered
B

3

38

I have a list ul>li*5 (not always the same amount). I set a counter for which I get:

1 2 3 4 5

li:nth-child(n):before {
  counter-increment: skill;
  content: counter(skill);
  color: white;
}

The Question Can I use the counter(skill) inside a calc() or can I add units to it px em rem % ms s

I have tried:

transition: all 250ms linear #{counter(skill)} * 1s;
transition: all 250ms linear counter(skill) * 1s;

I want to have the delay increased for example:

li 1s delay
li 2s delay
li 3s delay
li 4s delay
li Xs delay
Betjeman answered 21/4, 2017 at 9:38 Comment(2)
I don't think you can do that.Aran
Will there be a way to do this using the nth-child(N)Betjeman
M
71

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.

Mckamey answered 21/4, 2017 at 10:39 Comment(2)
The W3C issue "enable the use of counter() inside calc()"Graze
No attr() anymoreRazorback
B
23

This wouldn't necessarily be an elegant solution, but you could solve it with nth-child or using css variables. Code below, or see here: https://codepen.io/goodship11/pen/XBVeez

nth-child version:

li { 
  opacity: 0; 
  padding: 5px 0 5px 5px;
  list-style: none;
  background-color: rgba(200,50,255,.2);
  display: block;
  width: 20%;
  height: 10%;
}
li:nth-child(even) { background-color: rgba(200,50,255,.5); }

@keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } }

li { animation: fade 1.5s ease-in forwards; }

/* Since you're doing an animation, chances our the number 
of elements will be small, so you can just pre-define for however 
many versions using nth-child. This wouldn't work for use cases 
where, for example, you want a percentage of the whole instead 
of a fixed number */

li:nth-child(1) { animation-delay: 1s; }
li:nth-child(2) { animation-delay: 2s; }
li:nth-child(3) { animation-delay: 3s; }
li:nth-child(4) { animation-delay: 4s; }
li:nth-child(5) { animation-delay: 5s; }
li:nth-child(6) { animation-delay: 6s; }
li:nth-child(7) { animation-delay: 7s; }
li:nth-child(8) { animation-delay: 8s; }
<ul>
  <li>Thing 1</li>
  <li>Thing 2</li>
  <li>Thing 3</li>
  <li>Thing 4</li>
  <li>Thing 5</li>
</ul>

CSS variables version:

li { 
  opacity: 0; 
  padding: 5px 0 5px 5px;
  list-style: none;
  background-color: rgba(200,50,255,var(--fader));
  display: block;
  width: 20%;
  height: 10%;
}
@keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } }

li { animation: fade 1.5s ease-in forwards; }

/* Below is an alternative approach using the same variable 
from the opacity. I added in a scaling factor to show how you 
can use one variable for multiple things in cases like this.  */ 

:root {--factor: .5; }
li { animation-delay: calc(10s * var(--fader) * var(--factor));}
<ul>

  <!-- You can define the variable in-line, useful for in 
cases where you're writing the html manually but don't want to 
mess with the stylesheet. '--fader: .1' defines the variable 
for that instance of the li -->

  <li style="--fader: .1;">Thing 1</li>
  <li style="--fader: .2;">Thing 2</li>
  <li style="--fader: .3;">Thing 3</li>
  <li style="--fader: .4;">Thing 4</li>
  <li style="--fader: .5;">Thing 5</li>
</ul>
Bruce answered 30/7, 2018 at 14:41 Comment(0)
K
3

Here's a variation on goodship11's answer, except allowing for a dynamic number of elements (to avoid the need to create a potentially infinite number of nth-child css rules).

Dynamic version:

The example uses jQuery (so it's shorter) but it could just as easily done in plain ol' JavaScript (see the edit).

var i=0; 
$('#myList li').each(function(){
  this.style.setProperty('--n',i++);
})
li{opacity:0; animation:fadeIn 1s calc(var(--n)*1s) 1 forwards;}
@keyframes fadeIn{to{opacity:1}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<ul id="myList">
  <li>Thing 1</li>
  <li>Thing 2</li>
  <li>Thing 3</li>
  <li>Thing 4</li>
  <li>Thing 5</li>
</ul>

...or the loops could be written as a one-liner without the need for a variable, by instead using the element's index number:

$('#myList li').each(function(){this.style.setProperty('--n', Array.from($('#myList li')).indexOf(this))});


EDIT: while I'm at it, here's the "plain" JavaScript equivalent:

const lis=Array.from(myList.getElementsByTagName('li'));
for(var n=0; n<lis.length; n++){
  lis[n].style.setProperty('--n', n);
}
li{opacity:0; animation:fadeIn 1s calc(var(--n)*1s) 1 forwards;}
@keyframes fadeIn{to{opacity:1}}
<ul id="myList">
  <li>Thing 1</li>
  <li>Thing 2</li>
  <li>Thing 3</li>
  <li>Thing 4</li>
  <li>Thing 5</li>
</ul>
Kaitlinkaitlyn answered 7/11, 2022 at 20:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.