Security News
The Risks of Misguided Research in Supply Chain Security
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
css-counter-value
Advanced tools
Convert CSS counter()
values to integers
without JavaScript.
The limiting feature support required to use this utility is timeline-scope
.
css-counter-value
Features:counter()
value into an integer
for use in calc()
.counter()
contextually and be scoped all the way up on :root
so the whole site's CSS can mathematically respond to any counter anywhere.0
to 120
supported.:nth-*
selectors, elements can now mathematically respond to their GLOBAL index (<= 120).counter value
's scope to respond in any way you can think of, beyond mathematical manipulation.counter value
's scope itself to respond in non-mathematical ways? Run a mathematical comparitor then convert the resulting bit
into a Space Toggle using an animation like shown in the demo window here.$ npm install css-counter-value
Then include /node_modules/css-counter-value/counter-value.css
From html:
<link rel="stylesheet" type="text/css" href="https://unpkg.com/css-counter-value@2/counter-value.css">
@import url(https://unpkg.com/css-counter-value@2/counter-value.css);
Any element on the page can have a maximum of 8
converted counters host
ed in its scope
, each counter occupying a variable 1
through 8
.
var(--counter-value\\1)
var(--counter-value\\2)
var(--counter-value\\3)
var(--counter-value\\4)
var(--counter-value\\5)
var(--counter-value\\6)
var(--counter-value\\7)
var(--counter-value\\8)
For example, a td
might host
its table-row counter
(1) and its table-col counter
(2).
Additionally, the table
might host
the value of the counters of the last td
, effectively putting two more counters in scope
for the rest of the table
.
This rapidly enables the table (or grid, lists, etc) to know how many rows and columns it has without writing complex selectors to account for every potential count.
In this scenario, there would still 4
additional counters-value
s that could be converted in scope
of any td
on the table
.
css-counter-value
ExampleIf you prefer to dive into live code, check out this codepen.
Given this table, or a similarly structured grid, nested lists, or any other DOM tree (noting the inline styles managing the counter states):
<table>
<thead>...</thead>
<tbody style="counter-reset: table-row 0;">
<tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
</tr>
<tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
</tr>
</tbody>
</table>
To convert a counter into an integer, add a directive
as a descendant of the elment being counted and css-counter-value
's built in CSS interpreter
will assign the output counter-value\\*
vars as directed.
By default, without a matching host
in a directive
's context, the directive
will assign the converted counter-value
to var 1
(of 8
) on its immediate parent
, making the parent element an implicit host for the variable its setting:
<table>
<thead>...</thead>
<tbody style="counter-reset: table-row 0;">
<tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
<td style="counter-increment: table-col 1;">
<output data-counter-value style="--counter: table-col;"></output>
Know Thyself...?
</td>
</tr>
<tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
<td style="counter-increment: table-col 1;">
Who am I, really?
</td>
<td style="counter-increment: table-col 1;">
<output data-counter-value style="--counter: table-col;"></output>
Know Thyself...?
</td>
</tr>
</tbody>
</table>
The two td
elements with the data-counter-value
directive
inside of them now hold a CSS var var(--counter-value\\1)
with an integer value of 2
.
We set the --counter
variable to [the name of the counter]
we wish to convert using the style
attribute inline, but this can be done from your CSS if you prefer.
To add the row number, we must choose a variable slot not already in scope
(other than 1
in this case) and add another directive
to the td
's. To do this, assign the desired number 1
to 8
to the data-counter-value
attribute and set --counter
to the table-row
counter like so:
<td style="counter-increment: table-col 1;">
<output data-counter-value style="--counter: table-col;"></output>
<output data-counter-value="2" style="--counter: table-row;"></output>
Know Thyself.
</td>
The two td
elements now implicity host a second CSS var var(--counter-value\\2)
with an integer value of 1
or 2
depending on which row is looking.
data-counter-value="7"
would mean "set var(--counter-value\\7)
's value to [whatever counter name's value is specified]"
If we want our table
to know how many rows
and cols
it contains, we add a explicit host
directive attribute values
to the table
and, in the final td
, two directives
that set those values based on the counter()
states in their td
element's scope
:
<table data-counter-value="host:3 host:4">
...
<tbody style="counter-reset: table-row 0;">
...
<tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
..
<td style="counter-increment: table-col 1;">
<output data-counter-value style="--counter: table-col;"></output>
<output data-counter-value="2" style="--counter: table-row;"></output>
<output data-counter-value="3" style="--counter: table-col;"></output>
<output data-counter-value="4" style="--counter: table-row;"></output>
Know Thyself.
</td>
Assuming this is the last td
in the table
, the table
and every element inside of it will have access to var(--counter-value\\3)
(which contains and integer count of the total number of columns in the last row) and var(--counter-value\\4)
(which contains the integer total count of rows in the table).
Any of the 8
counter-value variables can be hosted on any ancestor, even :root
, and be set from any counter context within the host
element.
[!NOTE] Even though the
table-row
counter itself is stored on thetbody
, the wholetabel
has access to its integer counter value now.
Every td
can use both of these total count vars without adding the additional directives
because the --counter-value\\3
and --counter-value\\4
vars are inherited from table
.
[!CAUTION]
Any hosting element (matchingdata-counter-value*="host:"
) must nothost
the same variable as an ancestor. That is, for any given element's scope, it must not have more than one ancestor hosting the same counter-value variable1
to8
.
[!CAUTION] Within any given
host
element's context (descendants), there must not be more than onedirective
trying to set the samecounter-value
variable.
[!TIP] If your counters for a specific
counter-value
variable1
to8
are all0
values, the most likely scenario is a violation of either of the previous two rules.
Any number of sibling elements can host all 8
counter-value
variables for their own contexts as long as they don't have ancestors or descendants also trying to host one of the 8
variables.
For example, these three scenarios all break for the same reason:
<div data-counter-value="host:1 host:2 host:3">
<output data-counter-value="2" style="--counter: global-div-counter;"></output>
1
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is setting var 1, not implicitly on the parent, but explicitly to the ancestor hosting var 1 since it exists -->
2
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is setting var 1 to the same host, which is a conflict -->
3
</div>
</div>
and, very similar:
<div data-counter-value="host:1 host:2 host:3">
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is setting var 1 to its parent because the parent explicitly hosts var 1 -->
1
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is setting var 1 to the ancestor hosting var 1 since one exists -->
2
</div>
</div>
and, the tricky one:
<div data-counter-value="host:2 host:3">
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is setting var 1 to its parent implicitly -->
1
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- note this ^ is going to try setting var1 implicitly to its parent but will fail because an ancestor is implicity already hosting it -->
2
</div>
</div>
The following example is completely acceptable - there's a wide range of wild, exciting behavior still possible. We can have all sorts of fun within the established boundaries of this relationship, if you want 😉
<html data-counter-value="host:8">
...
<body style="counter-reset: global-div-counter: 0;">
<style>div { counter-increment: global-div-counter 1; }</style>
<div data-counter-value="host:3">
<output data-counter-value="2" style="--counter: global-div-counter;"></output>
<!-- var 2, implicitly on parent -->
1
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
2
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
<output data-counter-value="3" style="--counter: global-div-counter;"></output>
<!-- var 3, explicitly on an ancestor -->
3
</div>
</div>
<div data-counter-value="host:3">
<output data-counter-value="2" style="--counter: global-div-counter;"></output>
<!-- var 2, implicitly on parent -->
4
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
5
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
<output data-counter-value="3" style="--counter: global-div-counter;"></output>
<!-- var 3, explicitly on an ancestor -->
6
</div>
</div>
<div data-counter-value="host:3">
<output data-counter-value="2" style="--counter: global-div-counter;"></output>
<!-- var 2, implicitly on parent -->
7
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
8
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
9
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
10
</div>
<div>
<output data-counter-value style="--counter: global-div-counter;"></output>
<!-- var 1, implicitly on parent -->
<output data-counter-value="3" style="--counter: global-div-counter;"></output>
<!-- var 3, explicitly on an ancestor -->
<output data-counter-value="8" style="--counter: global-div-counter;"></output>
<!-- var 8, explicitly on :root, giving the whole document access to a variable var(--counter-value\\8) === 11 -->
11
</div>
</div>
Have fun!
Please do reach out if you need help with any of this, have feature requests, want to share what you've created, or wish to learn more.
PropJockey.io | CodePen | DEV Blog | GitHub | Mastodon |
---|---|---|---|---|
FAQs
Convert CSS counter() values to integers without JavaScript
The npm package css-counter-value receives a total of 16 weekly downloads. As such, css-counter-value popularity was classified as not popular.
We found that css-counter-value demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.