CSS变量(自定义属性)在伪元素“content”属性中的应用

57

示例用法(我想要的)

div::after {
  content: var(--mouse-x) ' / ' var(--mouse-y);
}

一个测试用例展示它不起作用的情况:

CodePen:Jase Smith的CSS伪元素“content:”属性中使用变量(一个测试用例)

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 {
  content: var(--mouse-x, 245)" / " var(--mouse-y, 327);
}

/* 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>


2
我建议直接在问题中发布代码,以防链接在未来失效。 - darrylyeo
啊,谢谢提示。我希望它只嵌入并展示 CodePen 演示... - Jase
这是一个重复的问题,https://dev59.com/Ipnga4cB1Zd3GeqPZ4cn,但由于你在处理数字,darrylyeo的hack方法完全可以胜任。 - BoltClock
4个回答

80

编辑以提高清晰度: 具有整数值的CSS自定义属性可以通过CSS计数器在伪元素的content属性中显示。

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>


原始回答

使用CSS 计数器的hack方法,让它可以工作了。享受吧。

div::after {
  counter-reset: mouse-x var(--mouse-x, 245) mouse-y var(--mouse-y, 245);
  content: counter(mouse-x) " / " counter(mouse-y);
}

全部代码演示:

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>


1
聪明的解决方案,只需从您的counter-reset属性中删除245值即可,它们是不必要的。 - Ricky Ruiz
啊!太棒了 :) 只有一个变量集,没有直接的 DOM 操作。喜欢它。非常感谢! - Jase
很高兴接受这个挑战! - darrylyeo
6
对于非整数值(例如 1.1),打印出 0 - vsync

8

content属性只允许传入字符串,因为你正在处理数字并且CSS无法转换变量类型,所以你需要创建另一组变量(来自JS),它们将作为打印值,并且是String类型。

要将--mouse-x-text设置为String,仅仅通过旧的类型转换技巧2+"" = "2"将其转换为该类型是不够的,但是JSON.stringify是我所知道的唯一可以从已经是字符串值的值中输出“真正”的字符串的方法,这种方法有点像一个字符串的字符串,因为CSS似乎会剥离第一个字符串层级。

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);
}


1
哦,那个JSON.stringify的技巧。我已经挣扎了好几个小时了。还有一个小提示,你可以像这样创建字符串:' " '+string+' " ' - santoshe61

7
我不确定我是否正确理解了你的问题,但我认为这里有一个解决方案...
您可以为<div>元素定义自定义属性。
<div data-position></div>

然后使用JavaScript将位置分配给此属性:
  var position = e.clientX + " " + e.clientY
  document.querySelector("div").setAttribute('data-position', position)

最后,在伪元素的content属性中使用attr() CSS函数。

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>


1
感谢@Ricky_Ruiz。对于我的帖子没有表述清楚,我表示歉意。虽然您的解决方案可以产生功能性结果,但我更有兴趣使用CSS自定义属性功能,而不是直接对元素(及其属性)进行DOM操作。 - Jase
@Jase,我明天早上会再试一次,看看能否提供符合您要求的答案。希望问题能够得到解决。我会保持更新。干杯! - Ricky Ruiz
@Jase,请查看DarryLeo的答案 - Ricky Ruiz

2

您需要在自定义属性的值周围加上引号。

document.documentElement.style.setProperty('--mouse-x', "'" + e.clientX + "'")
document.documentElement.style.setProperty('--mouse-y', "'" + e.clientY + "'")

然而,这似乎会破坏它作为int使用的定位,我猜CSS不像JS一样为您执行类型转换。 - DBS
1
这非常接近我想要的。然而,虽然这仅基于CSS变量提供了伪元素中值的实时更新,但DIV失去了其定位功能,正如@DBS所指出的那样,这有点让人失望。 - Jase
1
@Jase 显然这不是理想的解决方案,但你可以存储一个整数和一个字符串版本的相同值(例如,int 类型为“--mouse-x”,字符串类型为“--mouse-x-s”),并在需要时使用相关的数据类型。 - DBS
1
同意,目前没有办法使用一个变量集来完成这个任务。 - darrylyeo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接