39

I have been trying to get this to work for a while.

The point is that the inner div will have some shape and there will probably more than one (That's why I used the nth-child selector). This inner div is supposed to be shown and then be hidden again both for some set amount of time. the problem is, that I would like to animate all the (later) multiple inner divs in one animation. For this I thought I could use CSS variables, but this does not seem to work.

What I am trying to archieve in this example is the inner div basically just blinking by using the variable. But my result in Firefox is just a black box.

Am I missing anything? I already looked up if one could even use CSS variables in @keyframes and sure enough you can. The only problem with them in animations seems to be that they are not interpolated in between but that they suddenly switch which is not a problem in this case.

@keyframes test{
    from{
        --one: 0;
    }
    to{
        --one: 1;
    }
}

#test{
    width: 100px;
    height: 200px;
    background-color: black;
    animation: test 1s infinite;
}
#test :nth-child(1){
    width: 20px;
    height: 20px;
    margin: auto;
    background-color: white;
    opacity: var(--one,0);
}
<div id="test">
    <div></div>
</div>

0

2 Answers 2

72

This can be achieved by defining variables using (as of writing this, not well-supported) @property, which allows declaring types and that allows the browser to "understand", for example, that a certain property (variable) is a Number and then it can gradually animate/transition that variable.

Example Code:

@property --opacity {
  syntax: '<number>'; /* <- defined as type number for the transition to work */
  initial-value: 0;
  inherits: false;
}

@keyframes fadeIn {
  50% {--opacity: 1}
}

html {
  animation: 2s fadeIn infinite;
  background: rgba(0 0 0 / var(--opacity));
}

The current types that are allowed include:

length, number, percentage, length-percentage, color, image, url, integer, angle, time, resolution, transform-list, transform-function, custom-ident (an identifier string)


Helpful articles:

  1. https://web.dev/at-property/#writing-houdini-custom-properties
  2. https://css-tricks.com/using-property-for-css-custom-properties
  3. Cool Houdini demos
Sign up to request clarification or add additional context in comments.

6 Comments

cool, looking for that, and not find the MDN reference
Do you have any hints on how I could debug this? I think the property is not getting registered correctly for me. But I'm on Chrome 101 so it should be supported...
This works for me in Chrome but not in Firefox (v121).
FYI I couldn't get this to work before realising @property can only be defined at the root CSS level (not nested under any other selectors).
|
12

As stated in the specification:

Animatable: no

and also

Notably, they can even be transitioned or animated, but since the UA has no way to interpret their contents, they always use the "flips at 50%" behavior that is used for any other pair of values that can’t be intelligently interpolated. However, any custom property used in a @keyframes rule becomes animation-tainted, which affects how it is treated when referred to via the var() function in an animation property.


So even if you use opacity with var() in the keyframes it won't animate:

@keyframes test {
  from {
    --one:0;
    opacity: var(--one);
  }
  to {
    opacity: var(--one);
    --one: 1;
  }
}

#test {
  width: 100px;
  height: 200px;
  background-color: black;
}

#test :nth-child(1) {
  width: 20px;
  height: 20px;
  margin: auto;
  background-color: white;
  animation: test 1s  infinite;
  
}
<div id="test">
  <div></div>
</div>

By the way you can make it working if you use it as a transition because in this case you will apply a transtion to the opacity and not the custom property:

#test {
  width: 100px;
  height: 200px;
  background-color: black;
}

#test:hover {
  --one:1;
}

#test :nth-child(1) {
  width: 20px;
  height: 20px;
  margin: auto;
  background-color: white;
  opacity: var(--one,0);
  transition:1s all;
}
<div id="test">
  <div></div>
</div>

12 Comments

I thought that use the "flips at 50%" behavior would apply here. Why doesn't it? Because as I said that would be perfectly fine in this case. Maybe I don't understand animation tainted correctly.
@Johann150 to be honest the animation tainted is also confusing e :) I was searching a lot for this as me too I want to be able to animate custom property but after a lot of research, this was the only Specification section where I found it's not possible when using inside keyframes. BTW, let's wait, maybe you will get more answers ;)
Facing a related issue, and if I read the quoted text and the specs correctly, the animation-tainted thing only applies to the var() value when used in the animation property, it shouldn't affect the ones in the @keyframes, even though having it in the @keyframes is what makes it tainted for animation. Here is where it's being used. (Maybe it's a workaround for what could have been a source of infinite loop?). Note that your first example works perfectly fine in Firefox.
@Kaiido that issue cannot be in this scope because you are not animating any of the Custom properties but you are animating rotate(). In this case there is no animation-tainted. Even if you use var() inside animation there is also no animation-tainted behavior .. The specs says However, any custom property used in a @keyframes rule becomes animation-tainted --> it means used like --c:1 and not like property:var(-c). The last one is Ok.
I didn't mean the "related issue" was the same, only related and it's to give an idea of why I came here (an other discrepancy between browsers). My point is that "So even if you use opacity with var() in the keyframes it won't animate" is not true, or at least is not implied by the quote before. The quote only says that if you did --foo: 2s; animation: anim-name var(--foo) infinite; } @keyframes anim-name { from { --foo: 0s } to { --foo: 15s } } the value used in animation: anim-name var(--foo) infinite; } would remain 2s. It doesn't say that opacity should not use the updated value.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.