CSS动画填充模式-我做错了什么

CSS Animation Fill Mode - What have I done wrong?

本文关键字:错了 什么 动画 填充 模式 CSS      更新时间:2023-09-26

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

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

你知道我做错了什么吗?

我的代码笔:http://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>

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就不会跟踪(或知道什么)元素上先前存在的动画、它们的状态和填充模式等。一旦移除了动画,浏览器就会触发重新绘制,这将基于重绘时元素上存在的类来执行。因此,图元将捕捉回其未旋转的状态。你可以在我对类似问题的回答中阅读更多关于它的信息(但不相同:)。

为什么同一个关键帧不能用于反向动画(当具有原始动画的类没有被移除时)

这也是因为动画通常是如何工作的。当任何动画被添加到元素时,UA会保留有关动画的关键帧、状态等的详细信息,只要它被附加到元素即可。因此,除非删除添加正向(0°到180°)动画的类,否则浏览器会认为它已经执行完动画(默认迭代次数仅为1),因此即使添加了具有反向动画的类也不会执行任何操作。使其反向重新启动动画的唯一方法是删除带有正向动画的类,然后添加带有反向动画的类。你也可以看看这个答案来进行相关阅读。

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

进一步阅读:

  • 转换和动画之间有什么区别

  • 选择过渡或动画-何时使用哪个?


如果每次点击按钮都需要连续的顺时针或逆时针旋转(就像oMiKeY的回答中那样),那么我仍然建议使用带有JS的转换,就像下面的片段中一样。让我们把动画留给更复杂的东西(以及在没有任何触发器的情况下发生的特定东西)。

(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>

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

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

更改:

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')
)

并将类旋转填充模式添加到框中。虽然您可能只需要在动画类中保留填充模式。。。更新的代码笔:

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

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

看看我的小提琴: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>