【问题标题】:Why do my CSS variables not affect keyframes animation?为什么我的 CSS 变量不会影响关键帧动画?
【发布时间】:2020-10-06 02:59:17
【问题描述】:

我正在尝试使用 javascript 来更改关键帧动画的开始和结束度值。

在我的 CSS 文件的 :root 中,我为六个 div 中的每一个创建一个开始和结束变量,并分配一个初始值“0deg”。然后在我的 javascript 文件中,我每 3 秒更新一次每个变量。理论上这应该意味着每个 div 随机旋转 90 度。

但是,事实并非如此,我碰壁了。有趣的是,当我使用 getComputedStyle 将 CSS 旋转变量的值打印到控制台时,它们正确地反映了 javascript 创建的值。您可以在这里看到控制台正在记录与我的“rotate0a”和“rotate0b”公式相匹配的各种数字——左上角 div 的开始值和结束值。然而,该 div 会根据我在 :root 中设置的变量不断旋转。

CSS 转换不尊重新的变量值。任何帮助将不胜感激。谢谢!

下面的代码和这里的 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>

【问题讨论】:

    标签: javascript css animation css-animations


    【解决方案1】:

    在 Blink 和 Webkit 浏览器中,动画的值是在第一次设置动画时解析的,而不是在每次迭代时解析,也不是在变量更改时解析。

    你需要强制一个新的动画让它使用新的变量:

      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>

    请注意,Firefox 确实会实时更新值,并且这种动画并不是唯一在 Webkit+Blink 中遭受这种行为的动画(例如,我在更新 svg 引用的元素时遇到了很多问题)。虽然我不确定这里的规格要求是什么...


    (对 Chromium 进行一分为二,发现他们确实暴露了 FF 的行为(使用更新的 var() 值)直到 M54,here is the bug 发生了这种变化,因为那里没有提到这种行为,我猜这是一个副作用,可能是不需要的,打开 BUG 1135443)。

    【讨论】:

    • 成功了!非常感谢你。在让 js 与 CSS 正确通信方面,我是一个初学者。再次感谢您,希望此问答对其他人有所帮助。
    【解决方案2】:

    因为您正在从0deg 旋转到0deg,这意味着没有过渡。将您的变量更新为以下 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;
    }
    

    【讨论】:

      【解决方案3】:

      问题是,一旦你用animation: rotation0 1s infinite linear; 初始化动画,它就没有理由刷新它,并从 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&lt;6;t++)rotVarStarts[t]=rotVarEnds[t]}function setEnds(){for(let t=0;t&lt;6;t++)getRandomInt(),0==x?rotVar=0:1==x?rotVar=90:2==x?rotVar=180:3==x?rotVar=270:4==x&amp;&amp;(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));
        }
      }
      &lt;body onload = "setEnds()"&gt;&lt;div class = "wrapper"&gt;&lt;div class = "rotater zero"&gt;&lt;div class = "inner"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;

      我想知道你为什么不直接使用过渡而不是动画,就像这样:

      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&lt;6;t++)rotVarStarts[t]=rotVarEnds[t]}function setEnds(){for(let t=0;t&lt;6;t++)getRandomInt(),0==x?rotVar=0:1==x?rotVar=90:2==x?rotVar=180:3==x?rotVar=270:4==x&amp;&amp;(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%;
      }
      &lt;body onload = "setEnds()"&gt;&lt;div class = "wrapper"&gt;&lt;div class = "rotater zero"&gt;&lt;div class = "inner"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-04
        • 1970-01-01
        相关资源
        最近更新 更多