简体   繁体   English

为什么我的 CSS 变量不影响关键帧动画?

[英]Why do my CSS variables not affect keyframes animation?

I'm trying to use javascript to change the start and end degree values for keyframes animations.我正在尝试使用 javascript 来更改关键帧动画的开始和结束度值。

In :root in my CSS file I create a start and end variable for each of six divs and assign an initial value of "0deg".在我的 CSS 文件中的 :root 中,我为六个 div 中的每一个创建了一个开始和结束变量,并分配了一个初始值“0deg”。 Then in my javascript file I update each variable every 3 seconds.然后在我的 javascript 文件中,我每 3 秒更新一次每个变量。 Theoretically this should mean that each div randomly turns in 90 degree increments.从理论上讲,这应该意味着每个 div 以 90 度的增量随机转动。

But, that's not what's happening and I've hit a wall.但是,这不是正在发生的事情,我碰壁了。 Interestingly, when I print the values of my CSS rotation variables to the console using getComputedStyle, they are correctly reflecting the javascript-created values.有趣的是,当我使用 getComputedStyle 将 CSS 旋转变量的值打印到控制台时,它们正确地反映了 javascript 创建的值。 You can see here the console is logging a variety of numbers that match my formula for "rotate0a" and "rotate0b"--the start and end values for the top-left div.您可以在此处看到控制台正在记录与我的“rotate0a”和“rotate0b”公式相匹配的各种数字——左上角 div 的开始和结束值。 Yet that div continuously rotates according to the variable I set in :root.然而那个 div 会根据我在 :root 中设置的变量不断旋转。

The CSS transform isn't respecting the new variable values. CSS 转换不尊重新的变量值。 Any help would be hugely appreciated.任何帮助将不胜感激。 Thank you!谢谢!

Code below and CodePen version here: https://codepen.io/KylePalermo/pen/rNeENwd下面的代码和 CodePen 版本在这里: https ://codepen.io/KylePalermo/pen/rNeENwd

 let min = 0; let max = 4; let x; let rotVar; let rotVarStarts = [0, 0, 0, 0, 0, 0]; let rotVarEnds = []; function getRandomInt() { min = Math.ceil(min); max = Math.floor(max); x = Math.floor(Math.random() * (max - min) + min); } function resetStarts() { for (let i = 0; i < 6; i++) { rotVarStarts[i] = rotVarEnds[i]; } } function setEnds(){ for (let i = 0; i < 6; i++) { getRandomInt(); if (x == 0) { rotVar = 0; } else if (x == 1) { rotVar = 90; } else if (x == 2) { rotVar = 180; } else if (x == 3) { rotVar = 270; } else if (x == 4) { rotVar = 360; } rotVarEnds[i] = rotVar; } document.documentElement.style.setProperty('--rotate0a', rotVarStarts[0] + "deg"); document.documentElement.style.setProperty('--rotate0b', rotVarEnds[0] + "deg"); document.documentElement.style.setProperty('--rotate1a', rotVarStarts[1] +"deg"); document.documentElement.style.setProperty('--rotate1b', rotVarEnds[1] + "deg"); document.documentElement.style.setProperty('--rotate2a', rotVarStarts[2] + "deg"); document.documentElement.style.setProperty('--rotate2b', rotVarEnds[2] + "deg"); document.documentElement.style.setProperty('--rotate3a', rotVarStarts[3] + "deg"); document.documentElement.style.setProperty('--rotate3b', rotVarEnds[3] + "deg"); document.documentElement.style.setProperty('--rotate4a', rotVarStarts[4] + "deg"); document.documentElement.style.setProperty('--rotate4b', rotVarEnds[4] + "deg"); document.documentElement.style.setProperty('--rotate5a', rotVarStarts[5] + "deg"); document.documentElement.style.setProperty('--rotate5b', rotVarEnds[5] + "deg"); let test1 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0a'); let test2 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0b'); console.log(test1 + "//" + test2); } setInterval(function () { setEnds(); resetStarts(); }, 3000);
 :root { --rotate0a: 0deg; --rotate0b: 90deg; --rotate1a: 0deg; --rotate1b: 0deg; --rotate2a: 0deg; --rotate2b: 0deg; --rotate3a: 0deg; --rotate3b: 0deg; --rotate4a: 0deg; --rotate4b: 0deg; --rotate5a: 0deg; --rotate5b: 0deg; } .wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; } .rotater { width: 100%; background-color: blue; padding-bottom: 100%; position: relative; } .zero { animation: rotation0 1s infinite linear; } .one { animation: rotation1 1s infinite linear; } .two { animation: rotation2 1s infinite linear; } .three { animation: rotation3 1s infinite linear; } .four { animation: rotation4 1s infinite linear; } .five { animation: rotation5 1s infinite linear; } .inner { position: absolute; top: 0; left: 0; } @keyframes rotation0 { from { transform: rotate(var(--rotate0a)); } to { transform: rotate(var(--rotate0b)); } } @keyframes rotation1 { from { transform: rotate(var(--rotate1a)); } to { transform: rotate(var(--rotate1b)); } } @keyframes rotation2 { from { transform: rotate(var(--rotate2a)); } to { transform: rotate(var(--rotate2b)); } } @keyframes rotation3 { from { transform: rotate(var(--rotate3a)); } to { transform: rotate(var(--rotate3b)); } } @keyframes rotation4 { from { transform: rotate(var(--rotate4a)); } to { transform: rotate(var(--rotate4b)); } } @keyframes rotation5 { from { transform: rotate(var(--rotate5a)); } to { transform: rotate(var(--rotate5b)); } }
 <body onload = "setEnds()"> <div class = "wrapper"> <div class = "rotater zero"> <div class = "inner"></div> </div> <div class = "rotater one"> <div class = "inner"></div> </div> <div class = "rotater two"> <div class = "inner"></div> </div> <div class = "rotater three"> <div class = "inner"></div> </div> <div class = "rotater four"> <div class = "inner"></div> </div> <div class = "rotater five"> <div class = "inner"></div> </div> </div> </body>

Because you are rotating from 0deg to 0deg which means no transition.因为您正在从0deg旋转到0deg ,这意味着没有过渡。 Update your variables to following ant you will see it working:将您的变量更新为以下 ant,您将看到它正在工作:

:root {
  --rotate0a: 0deg;
  --rotate0b: 90deg;
  --rotate1a: 0deg;
  --rotate1b: 90deg;
  --rotate2a: 0deg;
  --rotate2b: 90deg;
  --rotate3a: 0deg;
  --rotate3b: 90deg;
  --rotate4a: 0deg;
  --rotate4b: 90deg;
  --rotate5a: 0deg;
  --rotate5b: 90deg;
}

The problem is once you initilized the animation with animation: rotation0 1s infinite linear;问题是一旦你用animation: rotation0 1s infinite linear;初始化animation: rotation0 1s infinite linear; it doesn't have a reason to refresh it, and picking up your updated values from js, you can easily see it changing if you force the css to start it on :hover (mouse hover to see):它没有理由刷新它,并从 js 中获取更新的值,如果您强制 css 在:hover (鼠标悬停以查看)上启动它,您可以很容易地看到它的变化:

 let x,rotVar,min=0,max=4,rotVarStarts=[0,0,0,0,0,0],rotVarEnds=[];function getRandomInt(){min=Math.ceil(min),max=Math.floor(max),x=Math.floor(Math.random()*(max-min)+min)}function resetStarts(){for(let t=0;t<6;t++)rotVarStarts[t]=rotVarEnds[t]}function setEnds(){for(let t=0;t<6;t++)getRandomInt(),0==x?rotVar=0:1==x?rotVar=90:2==x?rotVar=180:3==x?rotVar=270:4==x&&(rotVar=360),rotVarEnds[t]=rotVar;document.documentElement.style.setProperty("--rotate0a",rotVarStarts[0]+"deg"),document.documentElement.style.setProperty("--rotate0b",rotVarEnds[0]+"deg");let t=getComputedStyle(document.documentElement).getPropertyValue("--rotate0a"),e=getComputedStyle(document.documentElement).getPropertyValue("--rotate0b");console.log(t+"//"+e)}setInterval(function(){setEnds(),resetStarts()},3e3);
 :root { --rotate0a: 0deg; --rotate0b: 90deg; } .rotater { width: 100px; height: 50px; background-color: blue; position: relative; } .wrapper:hover .zero { animation: rotation0 1s infinite linear; } .inner { position: absolute; top: 0; left: 0; } @keyframes rotation0 { from { transform: rotate(var(--rotate0a)); } to { transform: rotate(var(--rotate0b)); } }
 <body onload = "setEnds()"><div class = "wrapper"><div class = "rotater zero"><div class = "inner"></div></div></body>

What I wonder is why won't you just use transition instead of animation, like so:我想知道为什么你不只是使用过渡而不是动画,像这样:

 let x,rotVar,min=0,max=4,rotVarStarts=[0,0,0,0,0,0],rotVarEnds=[];function getRandomInt(){min=Math.ceil(min),max=Math.floor(max),x=Math.floor(Math.random()*(max-min)+min)}function resetStarts(){for(let t=0;t<6;t++)rotVarStarts[t]=rotVarEnds[t]}function setEnds(){for(let t=0;t<6;t++)getRandomInt(),0==x?rotVar=0:1==x?rotVar=90:2==x?rotVar=180:3==x?rotVar=270:4==x&&(rotVar=360),rotVarEnds[t]=rotVar;document.documentElement.style.setProperty("--rotate0a",rotVarStarts[0]+"deg"),document.documentElement.style.setProperty("--rotate0b",rotVarEnds[0]+"deg");let t=getComputedStyle(document.documentElement).getPropertyValue("--rotate0a"),e=getComputedStyle(document.documentElement).getPropertyValue("--rotate0b");console.log(t+"//"+e)}setInterval(function(){setEnds(),resetStarts()},3e3);
 :root { --rotate0a: 0deg; --rotate0b: 90deg; } .rotater { width: 100px; height: 50px; background-color: blue; position: relative; transition: all 1s ease-in-out; } .zero { transform: rotate(var(--rotate0a)); } .inner { position: absolute; top: 0; left: 0; height: 100%; width: 100%; }
 <body onload = "setEnds()"><div class = "wrapper"><div class = "rotater zero"><div class = "inner"></div></div></body>

In Blink and Webkit browsers, the values for the animation are parsed the first time the animation is set and not at every iteration, nor when the variables change.在 Blink 和 Webkit 浏览器中,动画的值在第一次设置动画时解析,而不是在每次迭代时解析,也不在变量更改时解析。

You need to force a new animation for it to use the new variables:您需要强制一个新动画使用新变量:

  const rotaters = document.querySelectorAll('.rotater');
  rotaters.forEach( (elem) => {
    elem.style.animationName = "none";
  });
  //
  // update the variables here
  //
  document.body.offsetWidth; // force a single reflow
  rotaters.forEach( (elem, i) => {
    elem.style.animationName = "rotation" + i;
  });

 let min = 0; let max = 4; let x; let rotVar; let rotVarStarts = [0, 0, 0, 0, 0, 0]; let rotVarEnds = []; function getRandomInt() { min = Math.ceil(min); max = Math.floor(max); x = Math.floor(Math.random() * (max - min) + min); } function resetStarts() { for (let i = 0; i < 6; i++) { rotVarStarts[i] = rotVarEnds[i]; } } function setEnds(){ for (let i = 0; i < 6; i++) { getRandomInt(); if (x == 0) { rotVar = 0; } else if (x == 1) { rotVar = 90; } else if (x == 2) { rotVar = 180; } else if (x == 3) { rotVar = 270; } else if (x == 4) { rotVar = 360; } rotVarEnds[i] = rotVar; } const rotaters = document.querySelectorAll('.rotater'); rotaters.forEach( (elem) => { elem.style.animationName = "none"; }); document.documentElement.style.setProperty('--rotate0a', rotVarStarts[0] + "deg"); document.documentElement.style.setProperty('--rotate0b', rotVarEnds[0] + "deg"); document.documentElement.style.setProperty('--rotate1a', rotVarStarts[1] +"deg"); document.documentElement.style.setProperty('--rotate1b', rotVarEnds[1] + "deg"); document.documentElement.style.setProperty('--rotate2a', rotVarStarts[2] + "deg"); document.documentElement.style.setProperty('--rotate2b', rotVarEnds[2] + "deg"); document.documentElement.style.setProperty('--rotate3a', rotVarStarts[3] + "deg"); document.documentElement.style.setProperty('--rotate3b', rotVarEnds[3] + "deg"); document.documentElement.style.setProperty('--rotate4a', rotVarStarts[4] + "deg"); document.documentElement.style.setProperty('--rotate4b', rotVarEnds[4] + "deg"); document.documentElement.style.setProperty('--rotate5a', rotVarStarts[5] + "deg"); document.documentElement.style.setProperty('--rotate5b', rotVarEnds[5] + "deg"); let test1 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0a'); let test2 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0b'); console.log(test1 + "//" + test2); document.body.offsetWidth; // force a single reflow rotaters.forEach( (elem, i) => { elem.style.animationName = "rotation" + i; }); } setInterval(function () { setEnds(); resetStarts(); }, 3000);
 :root { --rotate0a: 0deg; --rotate0b: 90deg; --rotate1a: 0deg; --rotate1b: 0deg; --rotate2a: 0deg; --rotate2b: 0deg; --rotate3a: 0deg; --rotate3b: 0deg; --rotate4a: 0deg; --rotate4b: 0deg; --rotate5a: 0deg; --rotate5b: 0deg; } .wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; } .rotater { width: 100%; background-color: blue; padding-bottom: 100%; position: relative; } .zero { animation: rotation0 1s infinite linear; } .one { animation: rotation1 1s infinite linear; } .two { animation: rotation2 1s infinite linear; } .three { animation: rotation3 1s infinite linear; } .four { animation: rotation4 1s infinite linear; } .five { animation: rotation5 1s infinite linear; } .inner { position: absolute; top: 0; left: 0; } @keyframes rotation0 { from { transform: rotate(var(--rotate0a)); } to { transform: rotate(var(--rotate0b)); } } @keyframes rotation1 { from { transform: rotate(var(--rotate1a)); } to { transform: rotate(var(--rotate1b)); } } @keyframes rotation2 { from { transform: rotate(var(--rotate2a)); } to { transform: rotate(var(--rotate2b)); } } @keyframes rotation3 { from { transform: rotate(var(--rotate3a)); } to { transform: rotate(var(--rotate3b)); } } @keyframes rotation4 { from { transform: rotate(var(--rotate4a)); } to { transform: rotate(var(--rotate4b)); } } @keyframes rotation5 { from { transform: rotate(var(--rotate5a)); } to { transform: rotate(var(--rotate5b)); } }
 <body onload = "setEnds()"> <div class = "wrapper"> <div class = "rotater zero"> <div class = "inner"></div> </div> <div class = "rotater one"> <div class = "inner"></div> </div> <div class = "rotater two"> <div class = "inner"></div> </div> <div class = "rotater three"> <div class = "inner"></div> </div> <div class = "rotater four"> <div class = "inner"></div> </div> <div class = "rotater five"> <div class = "inner"></div> </div> </div> </body>

Note that Firefox does update the values live, and that this kind of animation is not the only one to suffer from this behavior in Webkit+Blink (I faced it a lot with updating svg referenced elements for instance).请注意,Firefox 会实时更新值,并且这种动画并不是 Webkit+Blink 中唯一受此行为影响的动画(例如,我在更新 svg 引用的元素时遇到了很多问题)。 Though I'm not sure what are the specs requirements here...虽然我不确定这里的规格要求是什么......


(Ran a bisect against Chromium and found they did expose FF's behavior (using updated var() values) until M54, here is the bug where this change happened, given there is nothing in there mentioning this behavior, I guess it's a side-effect, and maybe an unwanted one, opened BUG 1135443 ). (对 Chromium 进行了二等分,发现他们确实暴露了 FF 的行为(使用更新的 var() 值)直到 M54,这是发生这种变化的错误,因为那里没有提到这种行为,我想这是一个副作用,也许是不需要的,打开了BUG 1135443 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM