CSS Variables (custom properties) in Pseudo-element "content" Property
Edit for clarity: CSS custom properties with integer values can be displayed in a pseudo-element's content
property via a CSS counter.
div {
--variable: 123;
}
span:after {
counter-reset: variable var(--variable);
content: counter(variable);
}
<div>The variable is <span></span>.</div>
.coordinates:before {
counter-reset: x var(--x) y var(--y);
content: 'The coordinates are (' counter(x) ', ' counter(y) ').';
}
<div class="coordinates" style="--x: 1; --y: 2"></div>
Original Answer
Got it to work using a hack involving CSS Counters. Enjoy.
div::after {
counter-reset: mouse-x var(--mouse-x, 245) mouse-y var(--mouse-y, 245);
content: counter(mouse-x) " / " counter(mouse-y);
}
Full code in action:
document.addEventListener('mousemove', (e) => {
document.documentElement.style.setProperty('--mouse-x', e.clientX)
document.documentElement.style.setProperty('--mouse-y', e.clientY)
// output for explanation text
document.querySelector('.x').innerHTML = e.clientX
document.querySelector('.y').innerHTML = e.clientY
})
/* what I want!! */
div::after {
counter-reset: mouse-x var(--mouse-x, 245) mouse-y var(--mouse-y, 245);
content: counter(mouse-x) " / " counter(mouse-y);
}
/* setup and presentation styles */
div::before {
content: 'mouse position:';
}
div {
position: absolute;
top: 0;
left: 0;
transform: translate(calc(var(--mouse-x, 245) * 1px), calc(var(--mouse-y, 327) * 1px));
width: 10em;
height: 10em;
background: #ff3b80;
color: #fff;
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
border-radius: 100%;
will-change: transform;
}
body {
margin: 2em;
font-family: sans-serif;
}
p {
max-width: 50%;
min-width: 25em;
}
<!-- test case: element with pseudo element -->
<div></div>
<!-- explanation (not test case) -->
<main>
<pre><code>div::after {
content: var(--mouse-x) ' / ' var(--mouse-y);
}</code></pre>
<h1>If this worked...</h1>
<p>
We should see something like this: <b><span class="x">245</span> / <span class="y">327</span></b> updating with the mousemove coordinates inside the pseudo <i>::after</i> element for the div.
</p>
</main>
I'm not quite sure if I understood your question correctly, but I think here's a solution...
You can define a custom attribute to your <div>
element.
<div data-position></div>
Then assign the position in this attribute with javascript:
var position = e.clientX + " " + e.clientY
document.querySelector("div").setAttribute('data-position', position)
Finally use the attr()
CSS function in the content
property of your pseudoelement.
div::after {
content: attr(data-position);
}
And voila.
Code Snippet:
document.addEventListener('mousemove', (e) => {
document.documentElement.style.setProperty('--mouse-x', e.clientX)
document.documentElement.style.setProperty('--mouse-y', e.clientY)
var position = e.clientX + "/" + e.clientY
document.querySelector("div").setAttribute('data-position', position)
// output for explanation text
document.querySelector('.x').innerHTML = e.clientX
document.querySelector('.y').innerHTML = e.clientY
})
/* what I want!! */
div::after {
content: attr(data-position);
}
/* setup and presentation styles */
div::before {
content: 'mouse position:';
}
div {
position: absolute;
top: 0;
left: 0;
transform: translate(calc(var(--mouse-x, 245) * 1px), calc(var(--mouse-y, 327) * 1px));
width: 10em;
height: 10em;
background: #ff3b80;
color: #fff;
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
border-radius: 100%;
will-change: transform;
}
body {
margin: 2em;
font-family: sans-serif;
}
p {
max-width: 50%;
min-width: 25em;
}
<div data-position></div>
<span class="x"></span>/<span class="y"></span>
content
property only allows Strings, and since you are dealign with numbers and CSS cannot cast variables, you are left with the option to create another set of variables (from JS) which will serve as the printed values, and will be of type String
.
To set --mouse-x-text
as String
, it's not enough to cast it to that type using the old casting trick 2+"" = "2"
, but JSON.stringify
is the only way what I know that can output a "real" string, out of the already-string value, which kind-of mean a string of a string, since CSS seems to strip the first string-layer.
document.addEventListener('mousemove', ({clientX:x, clientY:y}) => {
const {style} = document.documentElement
style.setProperty('--mouse-x', x)
style.setProperty('--mouse-y', y)
// for printing
style.setProperty('--mouse-x-text', JSON.stringify(x+""))
style.setProperty('--mouse-y-text', JSON.stringify(y+""))
})
body::before{
content: "X:"var(--mouse-x-text)" Y:"var(--mouse-y-text);
}