Feature request.
It would be nice to be able to use the counter() function inside of calc() function.
That would enable new possibilities on layouts.
I copy here the link to a thread which proposed it last august.
https://lists.w3.org/Archives/Public/www-style/2016Aug/0073.html
Relevant section of the spec, which includes an inline issue discussing possible use cases. But getting an issue on GitHub will hopefully provide an easier forum for other people to mention their use cases and/or possible implementation issues.
Hi, ran into a case today where this would have helped, so posting a comment here.
I'm setting up some CSS for an image/logo slider. While I know right now that there are 8 images, I don't know how many there will be in the future (nor do I wish to have to know). I'm using only CSS to animate it, and it would be useful to be able to say "for each one of the items that exist (, increment this property by x."
I ended up using sass to do something like this:
```
@for $i from 1 through 8 {
&:nth-of-type(#{$i}) {
$delay: calc(5s * #{$i});
animation: slideIn 45s linear $delay infinite;
}
}
The problem with this proposal is that counter()
returns a <string>
, but calc()
does not work with strings. For example, counter(id, upper-latin)
might be 'A'
. How exactly is calc()
supposed to know that this means 1
?
So I think we need some way to get the numeric value of a counter, either by adding some parameter to counter()
or a new function. This should be allowed to appear anywhere an integer is expected, including (but not necessarily in) calc()
. I wrote my thoughts in #1871.
JFTR, I would hate to see int()
or str2num()
in CSS.
Yeah, an explicit parsing function is probably bad. No real need for it. But having something that can retrieve a counter value as a number (rather than going to the extra effort of formatting it as a string) would work. (Same as how attr()
has functionality to parse the attr value as a number or dimension.)
Wouldn't allowing counter()
in calc()
either ruin any attempt to parallelize styling, or make us need to delay calculating of every numeric value to used-value time?
@upsuper Fair point, counter values are inherited from the immediately preceding element in document order instead of from the parent element as usual. So maybe it would be better to add a sibling-index()
function as Tab Atkins proposed in https://github.com/w3c/csswg-drafts/issues/1869#issuecomment-340078522; it would be less powerful but I think it would cover most usecases.
However, note that the CSS Lists draft currently allows counter()
anywhere a <string>
is expected, doesn't this have the same problem? If it's possible to use a counter value as a string, it should also be possible to use it as an integer.
However, note that the CSS Lists draft currently allows
counter()
anywhere a<string>
is expected, doesn't this have the same problem? If it's possible to use a counter value as a string, it should also be possible to use it as an integer.
Firstly, there are a lot fewer places where <string>
is accepted, and they are usually relatively less complicated than <length>
and its friends when it comes to layout, so expanding them in used-value time (like what is currently done for content
property) may not be as bad.
Also, allowing counter()
anywhere <string>
is allowed is something new. counter()
functions are listed as independent item of content
property in CSS2. And I'm not aware of any browser who has implemented that anywhere outside content
. That means, its feasibility may also be questioned, and my argument above can potentially be apply to that as well.
Firstly, there are a lot fewer places where
<string>
is accepted, and they are usually relatively less complicated than<length>
and its friends when it comes to layout, so expanding them in used-value time (like what is currently done for content property) may not be as bad.
It may not be as bad, but it could still be very bad. One issue comes to my mind is that <family-name>
can be a <string>
, and font-family
is inherited, so you may really want to make counter()
be expanded in computed-value time (rather than in used-value time like what we do now for content
), otherwise it can lead to some funny behavior. This is some case which seems to be neither useful nor easy to implement, which would be a native consequence if we allow counter()
be in anywhere <string>
is allowed.
I guess we should start this topic in a separate issue, now.
I would really, really love to have counter's value available inside calc()
. The syntax I'd propose could be something like counter-value()
that would return the counter's value as an integer. Other than the use-cases for sibling-index
, this could be used for a lot more cases (not only experimental ones). While I understand that that can be non-trivial to implement, the possibilities it would unlock would be tremendous.
Two more use cases:
animation-delay
z-index
Regarding syntax, I like @tabatkins's proposal for a new formatting argument, if an explicit syntax is required.
Although IMO ideally it would be nice if we could auto cast number-like strings to numbers in calc()
akin to how many programming languages do it (including JS). It's not like strings actually do anything in calc()
, so there's no disambiguation problem.
My sad excuse of a utility without this feature...
...
.count--3 { --count: 3 }
.count--4 { --count: 4 }
.count--5 { --count: 5 }
...
.count > :nth-child(1) { --count-current: 1 }
.count > :nth-child(2) { --count-current: 2 }
.count > :nth-child(3) { --count-current: 3 }
...
.el {
animation-delay: calc((var(--count, 0) - var(--count-current, 0)) * 0.1s);
}
I like this in general and I'd love to see it implemented too. But I'd really, really hate implementing it.
All of the paged media layout engines have the same problem with counters, in particular "page" and "pages", although technically it's any counters incremented in the @page margin areas (still a largely theoretical constraint at the time of writing). The moment you hit one of these you have to consider a second layout pass - it's not always required, but for something like span::after { content: counter(pages upper-roman); }
you really haven't got much choice.
You need the first layout pass to count the pages, or to work out with certainty which page your element is on (that's more of an issue with target-counter(nnn, page)
to be fair). But once you start introducing counters to other properties - say margin-top: calc(counter(pages) * 20px)
- you've introduced a loop: layout depends on values computed from an earlier pass of the layout, and so on.
It's not quite as awful for the "page" counter, or any counter other than "pages". But it's still a little complex: orphans: calc(counter(page) * 20)
may force a page-break, which would change the value of orphans...
So although I'm not exactly against this, I just wanted to flag that it is almost unfeasibly hairy for some cases. Think of the multiple passes required to stabilise layout for ::first-line, except it's a _whole document_ that needs to be stabilised. These would need to be considered if this goes anywhere.
Won鈥檛 we get this for free once we have a function to convert between types, the likes of which has been discussed multiple times?
I landed here because I assumed I would be able to do something like this in CSS:
li:nth-child(n) {
background-color: hsl(calc(10 *n), 100%, 70%);
}
Most helpful comment
Two more use cases:
animation-delay
z-index
Regarding syntax, I like @tabatkins's proposal for a new formatting argument, if an explicit syntax is required.
Although IMO ideally it would be nice if we could auto cast number-like strings to numbers in
calc()
akin to how many programming languages do it (including JS). It's not like strings actually do anything incalc()
, so there's no disambiguation problem.