【问题标题】:CSS Animation Fill Mode - What have I done wrong?CSS动画填充模式 - 我做错了什么?
【发布时间】:2016-01-06 14:47:26
【问题描述】:

我需要创建一个旋转动画。单击事件将元素旋转 180° 以指向下方。另一个点击事件将同一元素旋转回 0° 以指向上方。

我将animation-fill-mode 设置为forwards 以保留最后一个关键帧状态。但它似乎没有工作。所有视觉元素都重置为默认状态。

任何想法我可能做错了什么?

我的 Codepenhttp://codepen.io/simspace-dev/pen/RrpGmP

我的代码

(function() {
  $('#btnb').on('click', function(e) {
    return $('.box').addClass('spin-counter-clockwise');
  });
  $('#btnf').on('click', function(e) {
    return $('.box').addClass('spin-clockwise');
  });
  $('.box').on('webkitAnimationEnd', function(e) {
    return $(e.target).removeClass('spin-counter-clockwise').removeClass('spin-clockwise');
  });
}.call(this));
.box {
  background: red;
  position: relative;
  width: 176px;
  height: 176px;
  margin: 40px auto;
  text-align: center;
}
.box .top {
  background: green;
  position: absolute;
  top: 0;
  width: 100%;
  height: 28px;
}
.box .bottom {
  background: purple;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 28px;
}
.box .caret {
  color: white;
  font-size: 88px;
  position: absolute;
  top: 42px;
  left: 50px;
}
.spin-clockwise {
  -moz-animation: spin 2s;
  -webkit-animation: spin 2s;
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
}
.spin-counter-clockwise {
  -moz-animation: spin 2s reverse;
  -webkit-animation: spin 2s reverse;
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
}
@keyframes spin {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
}
body {
  text-align: center;
  margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>

<div class="box">
  <div class="top">top</div>
  <div class="caret"><i class="fa fa-caret-square-o-up"></i>
  </div>
  <div class="bottom">bottom</div>
</div>

<p>
  <button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
  <button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>

【问题讨论】:

  • 您使用动画有什么特别的原因吗?使用过渡而不是动画来实现这一点会容易得多。
  • 谢谢哈利,我会研究过渡。
  • 感谢 Harry、Chris 和 oMiKeY 的精彩回答!如果事实证明我使用了转换(这听起来是更好的方法),我仍然很高兴我尝试了这条路线来获得学习体验。在此之前我从来没有搞乱过 CSS 动画,我学到了很多东西。

标签: javascript jquery css css-animations


【解决方案1】:

TL;DR:(直接到建议的解决方案)

如果您只需要单击一个按钮将旋转从 0° 旋转到 180°,然后单击另一个按钮从 180° 返回到 0°,那么我建议使用过渡而不是动画。默认情况下,转换会产生相反的效果,因此无需为两种不同的状态编写代码(这使它变得更好)。

(function() {
  $('#btnb').on('click', function(e) {
    return $('.box').removeClass('spin');
  });
  $('#btnf').on('click', function(e) {
    return $('.box').addClass('spin');
  });
}.call(this));
.box {
  background: red;
  position: relative;
  width: 176px;
  height: 176px;
  margin: 40px auto;
  text-align: center;
  transition: transform 1s linear;
  /* add this to enable transition */
}
.box .top {
  background: green;
  position: absolute;
  top: 0;
  width: 100%;
  height: 28px;
}
.box .bottom {
  background: purple;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 28px;
}
.box .caret {
  color: white;
  font-size: 88px;
  position: absolute;
  top: 42px;
  left: 50px;
}
.spin {
  /* this is the only thing required for rotation (along with the JS) */
  transform: rotate(180deg);
}
body {
  text-align: center;
  margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>

<div class="box">
  <div class="top">top</div>
  <div class="caret"><i class="fa fa-caret-square-o-up"></i>
  </div>
  <div class="bottom">bottom</div>
</div>

<p>
  <button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
  <button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>

如果您仅出于学习目的使用动画,那么下面提供的详细信息对您了解动画的工作原理、由此产生的限制等方面仍然有用。


Chris 的回答触及了您的问题的原因,但我认为这个问题值得对两件事进行更详细的解释 - (1) 为什么即使 animation-fill-mode: forwards 元素不保持最后一个关键帧的状态设置被应用 (2) 为什么相同的关键帧不能用于反向动画(当没有删除带有原始动画的类时)。我还想提出一个不同的替代方案来替代整个事情,从而给出单独的答案。

为什么即使填充模式设置为向前,元素也不保持最后一个关键帧的状态?

这是因为您将在动画完成后立即删除添加动画的类(在on('webkitAnimationEnd') 事件处理程序内)。通常当animation-fill-mode 设置为forwards 时,UA 使用在最后一个关键帧中提供的设置(或属性值对)来维持状态。但是一旦类被移除(以及动画设置),UA 就不会跟踪(或知道什么)元素上先前存在的动画、它们的状态和填充模式等。一旦动画被移除,浏览器触发重绘,这将根据重绘时元素上存在的类执行。因此,该元素将迅速恢复到其未旋转状态。您可以在我对类似问题的回答 here 中阅读更多相关信息(但不一样:))。

为什么不能将相同的关键帧用于反向动画(当没有删除具有原始动画的类时)?

这又是因为动画通常是如何工作的。当任何动画被添加到元素时,UA 会维护有关动画关键帧、其状态等的详细信息,只要它附加到元素。因此,除非删除添加正向(0° 到 180°)动画的类,否则浏览器会认为它已将动画执行到完成(因为默认迭代计数仅为 1),因此即使具有反向动画的类添加,它什么也不做。使它反向重新启动动画的唯一方法是删除具有正向动画的类,然后添加具有反向动画的类。您也可以查看this answer 进行相关阅读。

由于上述原因,实现动画所需的唯一方法是为正向和反向动画创建两个不同的动画(或关键帧),将它们设置在两个不同的类下,并使用 JavaScript 不断更改类。整个过程变得乏味,当您只需单击一个按钮从(0° 到 180°)旋转并从另一个(180° 到 0°)旋转回来时,通常不需要。整个事情都可以使用转换来实现,而让这一点变得更好的是,默认情况下转换会产生相反的效果,因此无需为两种不同的状态编写代码。

进一步阅读:


如果需要在每次单击按钮时连续顺时针或逆时针旋转(如在 oMiKeY 的回答中),那么我仍然建议使用带有一点 JS 的转换,如下面的 sn-p 所示。让我们为更复杂的内容(以及在没有任何触发器的情况下发生的特定内容)保留动画。

(function() {
  var deg = 0;
  $('#btnb').on('click', function(e) {
    deg -= 180;
    return $('.box').css('transform', 'rotate(' + deg + 'deg)');
  });
  $('#btnf').on('click', function(e) {
    deg += 180;
    return $('.box').css('transform', 'rotate(' + deg + 'deg)');
  });
}.call(this));
.box {
  background: red;
  position: relative;
  width: 176px;
  height: 176px;
  margin: 40px auto;
  text-align: center;
  transition: transform 1s linear;  /* add this to enable transition */
}
.box .top {
  background: green;
  position: absolute;
  top: 0;
  width: 100%;
  height: 28px;
}
.box .bottom {
  background: purple;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 28px;
}
.box .caret {
  color: white;
  font-size: 88px;
  position: absolute;
  top: 42px;
  left: 50px;
}
body {
  text-align: center;
  margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Keyframes are not supported in IE9 and earlier</h2>

<div class="box">
  <div class="top">top</div>
  <div class="caret"><i class="fa fa-caret-square-o-up"></i>
  </div>
  <div class="bottom">bottom</div>
</div>

<p>
  <button id="btnf">SPIN CLOCKWISE</button>
</p>
<p>
  <button id="btnb">SPIN COUTNER CLOCKWISE</button>
</p>

【讨论】:

  • 很好的解释哈利。谢谢。
【解决方案2】:

所以根本问题是动画类被删除了。

我无法使用相同的关键帧让它工作,但我所做的是为逆时针创建一个新的关键帧,然后在单击按钮时删除相反的类

变化:

css

.spin-clockwise {


-moz-animation: spin 2s;
  -webkit-animation: spin 2s;

}

.spin-fill-mode {
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
  animation-fill-mode: forwards;
}

.spin-counter-clockwise {
  -moz-animation: spin-counter 2s; 
  -webkit-animation: spin-counter 2s; 

}

@keyframes spin {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
}

@keyframes spin-counter {
  from {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
  to {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
}

js:

$('#btnb').on('click', (e)->


$('.box')
    .addClass('spin-counter-clockwise')
    .removeClass('spin-clockwise')
)

$('#btnf').on('click', (e) ->
  $('.box')
    .addClass('spin-clockwise')
    .removeClass('spin-counter-clockwise')
)

并将类 spin-fill-mode 添加到 box。虽然您可能只是将填充模式留在动画类中...... 更新代码笔:

http://codepen.io/anon/pen/QypvOr

【讨论】:

  • 太棒了!谢谢。
【解决方案3】:

我摆弄了一会儿,然后决定你可能需要两个单独的旋转动画。

看看我的小提琴:http://codepen.io/anon/pen/jWBmZK

(function() {
  $('#btnb').on('click', function(e) {
    return $('.box')
    .addClass('spin-counter-clockwise')
    .toggleClass('upside-down');
  });
  $('#btnf').on('click', function(e) {
    return $('.box')
    .addClass('spin-clockwise')
    .toggleClass('upside-down');
  });
  $('.box').on('webkitAnimationEnd', function(e) {
    return $(e.target).removeClass('spin-counter-clockwise').removeClass('spin-clockwise');
  });
}.call(this));
.box {
  background: red;
  position: relative;
  width: 176px;
  height: 176px;
  margin: 40px auto;
  text-align: center;
}
.box .top {
  background: green;
  position: absolute;
  top: 0;
  width: 100%;
  height: 28px;
}
.box .bottom {
  background: purple;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 28px;
}
.box .caret {
  color: white;
  font-size: 88px;
  position: absolute;
  top: 42px;
  left: 50px;
}
.upside-down {
    -moz-transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    transform: rotate(180deg);
}
.spin-clockwise.upside-down {
  -moz-animation: spin 2s;
  -webkit-animation: spin 2s;
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;

}
.spin-counter-clockwise {
  -moz-animation: spin 2s reverse; 
  -webkit-animation: spin 2s reverse; 
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;

}
.spin-clockwise {
  -moz-animation: back-spin 2s;
  -webkit-animation: back-spin 2s;
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
}
.spin-counter-clockwise.upside-down {
  -moz-animation: back-spin 2s reverse; 
  -webkit-animation: back-spin 2s reverse; 
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
}
@keyframes spin {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
}
@keyframes back-spin {
  from {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
body {
  text-align: center;
  margin: 0 auto;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>

<body>

  <h2>Keyframes are not supported in IE9 and earlier</h2>

  <div class="box">
    <div class="top">top</div>
    <div class="caret"><i class="fa fa-caret-square-o-up"></i>
    </div>
    <div class="bottom">bottom</div>
  </div>

  <p>
    <button id="btnf">SPIN CLOCKWISE</button>
  </p>
  <p>
    <button id="btnb">SPIN COUTNER CLOCKWISE</button>
  </p>
</body>

</html>

【讨论】:

  • 基于@Harry 的 cmets,我决定使用转换而不是 css 动画。我使用转换创建了另一个 Codepen 示例:codepen.io/simspace-dev/pen/XXMqwB 还使用动画更新了我以前的 Codepen 以如上所述工作:codepen.io/simspace-dev/pen/RrpGmP
  • 我的可以无限旋转,而他的不会:P...jk 这是一个有趣的工作,谢谢你的好问题。
猜你喜欢
  • 2014-02-22
  • 2020-09-27
  • 2014-11-23
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 2019-10-19
  • 1970-01-01
相关资源
最近更新 更多