仅当目标值发生变化时才应用过渡时间

Transition time is only applied if target value changes

Note: I updated the question with a simpler example as I found that it is not an issue with transform in particular, but with how the transition timing is applied. You can still see the more complex example in the edit history.

举个简单的例子:当鼠标悬停在"Grow"按钮上时,该条会在5秒内增长到400px;并且退出"Grow"按钮后,bar会在10秒后自动缩小到0px。如果您将鼠标悬停在 "Shrink" 按钮上,该栏将在 2 秒内缩小到 0px。

虽然没有,但即使将鼠标悬停在上面也需要 10 秒才能返回到 0px "Shrink":

#bar {
  width:0;
  border-left:1px solid gray;
  height: 40px;
  transition: width 10s;
  background: green;
}

#grow,#shrink {
  display:inline-block;
  width: 60px;
  height: 60px;
  background: gray;
  margin-bottom: 10px;
  color: white;
  line-height: 60px;
  text-align: center;
  box-shadow: inset 0 0 0 1px black;
  margin-right: 20px;
}

#grow:hover ~ #bar {
  width: 400px;
  transition: width 5s;
}

#shrink:hover ~ #bar {
  width: 0px;
  transition: width 2s;
}
<span id="grow">Grow</span>
<span id="shrink">Shrink</span>

<div id="bar"></div>

起初我认为这可能是特异性的问题(即使 #shrink:hover ~ #bar#bar 更具体),所以我添加了一个 !important 像这样:

#shrink:hover ~ #bar {
  width: 0px;
  transition: width 2s !important;
}

还是不行。经过一些尝试错误后,我发现更改值实际上会使浏览器采用新的过渡时间,即使更改微不足道。因此,例如,这将起作用:

#bar {
  width:0;
  border-left:1px solid gray;
  height: 40px;
  transition: width 10s;
  background: green;
}

#grow,#shrink {
  display:inline-block;
  width: 60px;
  height: 60px;
  background: gray;
  margin-bottom: 10px;
  color: white;
  line-height: 60px;
  text-align: center;
  box-shadow: inset 0 0 0 1px black;
  margin-right: 20px;
}

#grow:hover ~ #bar {
  width: 400px;
  transition: width 5s;
}

#shrink:hover ~ #bar {
  width: 0.000001px;
  transition: width 2s;
}
<span id="grow">Grow</span>
<span id="shrink">Shrink</span>

<div id="bar"></div>

行得通。另外,我注意到它工作的另一种情况:当它直接从 "Grow" 到 "Shrink" 而不过渡到其他任何东西时(你可以通过从 "Grow" 移动到 "Shrink" 非常快或通过删除边距使它们在一起)。

我已经能够在 Chrome、Internet Explorer/Edge、Firefox 和 Safari 中重现此问题。所以我不知道这是一个真正的问题还是我误解了它应该如何工作(也很有可能)。

为什么会这样?有没有办法在不更改目标值的情况下应用新的过渡时间?

我仍在挖掘,但这是我的结论。

首先,这可能只是一个错误。这总是可能的。

但是,如果我们假设它正常运行,我认为真正的原因是 "identical keyframes"。

你看,不是rotate()函数的角度问题。 transform 属性 与 #arm#brake 几乎相同。如果我想象 css 解析您的动画样式并创建 "keyframes",它可能会认为第一个定义与第二个定义相同。

如果我们向这两个声明之一添加一个完全无用但唯一的函数,那么它们将被视为两个唯一的关键帧并按您希望的方式运行。这就是您将角度减小 1 度所做的事情。

@import url("https://fonts.googleapis.com/css?family=Oswald|VT323");

.round {
  border-radius: 100%;
}

.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  box-sizing: border-box;
}

#board {
  width: 300px;
  height: 300px;
  background: white;
  border: 12px solid black;
  overflow: hidden;
  box-shadow: inset 0 0 0 12px red;
}

#pointer {
  z-index: 1;
}

#knot {
  width: 20px;
  height: 20px;
  background: black;
  z-index: 2;
}

#arm {
  width: 126px;
  height: 6px;
  background: red;
  transform: translate(-85%, -50%) rotate(-42deg);
  border-radius: 80% 6px 6px 80%;
  transform-origin: 85% 50%;
  transition: transform 14s;
}

#speed:hover~#board #pointer #arm {
  transform: translate(-85%, -50%) rotate(62deg);
  transition: transform 7s;
}

#brake:hover~#board #pointer #arm {
  transform: translate(-85%, -50%) rotate(-42deg) rotateX(0);/* I added this useless rotateX() */
  transition: transform 3s;
}

.bar {
  width: 300px;
  height: 2.30769px;
}

.bar:nth-of-type(4n+1) {
  height: 4.61538px;
}

.bar::after {
  content: "";
  position: absolute;
  left: 20px;
  height: 100%;
  width: 12px;
  background: black;
}

.bar:nth-of-type(odd)::after {
  width: 15.78947px;
}

.bar:nth-of-type(1) {
  transform: translate(-50%, -50%) rotate(-42deg);
}

.bar:nth-of-type(2) {
  transform: translate(-50%, -50%) rotate(-34deg);
}

.bar:nth-of-type(3) {
  transform: translate(-50%, -50%) rotate(-26deg);
}

.bar:nth-of-type(4) {
  transform: translate(-50%, -50%) rotate(-18deg);
}

.bar:nth-of-type(5) {
  transform: translate(-50%, -50%) rotate(-10deg);
}

.bar:nth-of-type(6) {
  transform: translate(-50%, -50%) rotate(-2deg);
}

.bar:nth-of-type(7) {
  transform: translate(-50%, -50%) rotate(6deg);
}

.bar:nth-of-type(8) {
  transform: translate(-50%, -50%) rotate(14deg);
}

.bar:nth-of-type(9) {
  transform: translate(-50%, -50%) rotate(22deg);
}

.bar:nth-of-type(10) {
  transform: translate(-50%, -50%) rotate(30deg);
}

.bar:nth-of-type(11) {
  transform: translate(-50%, -50%) rotate(38deg);
}

.bar:nth-of-type(12) {
  transform: translate(-50%, -50%) rotate(46deg);
}

.bar:nth-of-type(13) {
  transform: translate(-50%, -50%) rotate(54deg);
}

.bar:nth-of-type(14) {
  transform: translate(-50%, -50%) rotate(62deg);
}

.bar:nth-of-type(15) {
  transform: translate(-50%, -50%) rotate(70deg);
}

.bar:nth-of-type(16) {
  transform: translate(-50%, -50%) rotate(78deg);
}

.bar:nth-of-type(17) {
  transform: translate(-50%, -50%) rotate(86deg);
}

.bar:nth-of-type(18) {
  transform: translate(-50%, -50%) rotate(94deg);
}

.bar:nth-of-type(19) {
  transform: translate(-50%, -50%) rotate(102deg);
}

.bar:nth-of-type(20) {
  transform: translate(-50%, -50%) rotate(110deg);
}

.bar:nth-of-type(21) {
  transform: translate(-50%, -50%) rotate(118deg);
}

.bar:nth-of-type(22) {
  transform: translate(-50%, -50%) rotate(126deg);
}

.bar:nth-of-type(23) {
  transform: translate(-50%, -50%) rotate(134deg);
}

.bar:nth-of-type(24) {
  transform: translate(-50%, -50%) rotate(142deg);
}

.bar:nth-of-type(25) {
  transform: translate(-50%, -50%) rotate(150deg);
}

.bar:nth-of-type(26) {
  transform: translate(-50%, -50%) rotate(158deg);
}

.bar:nth-of-type(27) {
  transform: translate(-50%, -50%) rotate(166deg);
}

.bar:nth-of-type(28) {
  transform: translate(-50%, -50%) rotate(174deg);
}

.bar:nth-of-type(29) {
  transform: translate(-50%, -50%) rotate(182deg);
}

.bar:nth-of-type(30) {
  transform: translate(-50%, -50%) rotate(190deg);
}

.bar:nth-of-type(31) {
  transform: translate(-50%, -50%) rotate(198deg);
}

.bar:nth-of-type(32) {
  transform: translate(-50%, -50%) rotate(206deg);
}

.bar:nth-of-type(33) {
  transform: translate(-50%, -50%) rotate(214deg);
}

.num {
  font-family: Oswald, Arial, Verdana, sans-serif;
  font-weight: bold;
  text-align: center;
  font-size: 1.3em;
  position: absolute;
}

.num:nth-of-type(1) {
  top: 66.66667px;
  left: -75px;
}

.num:nth-of-type(2) {
  top: 16.66667px;
  left: -96.77419px;
}

.num:nth-of-type(3) {
  top: -37.5px;
  left: -92.30769px;
}

.num:nth-of-type(4) {
  top: -78.94737px;
  left: -60px;
}

.num:nth-of-type(5) {
  top: -100px;
  left: -7.5px;
}

.num:nth-of-type(6) {
  top: -85.71429px;
  left: 42.85714px;
}

.num:nth-of-type(7) {
  top: -50px;
  left: 78.94737px;
}

.num:nth-of-type(8) {
  top: 3.75px;
  left: 93.75px;
}

.num:nth-of-type(9) {
  top: 51.72414px;
  left: 76.92308px;
}

#mileage {
  padding-top: 187.5px;
}

#box {
  width: 75px;
  height: 25px;
  background: black;
  display: inline-block;
  float: left;
  color: rgba(200, 255, 0, 0.8);
  line-height: 1.2em;
  text-align: right;
  padding-right: 0.325em;
  box-sizing: border-box;
  font-family: VT323, Oswald;
  font-size: 1.3em;
  margin-left: 1em;
}

#miles {
  float: left;
  line-height: 25px;
  margin-left: 0.325em;
  font-family: Oswald, Arial, Verdana, sans-serif;
  font-size: 1em;
}

#red-bar {
  width: 200%;
  height: 200%;
  background: white;
  border-radius: 100% 0 0;
  transform: translate(-101%, -61.7%) rotate(28deg);
}

#red-bar::before {
  content: "";
  background-color: white;
  display: block;
  width: 50%;
  height: 50%;
  position: absolute;
  bottom: 0;
  right: 0;
  transform: translate(86%, -22.5%) rotate(97deg);
}

#speed,
#brake {
  text-align: center;
  line-height: 100px;
  font-family: Oswald, Arial, Verdana, sans-serif;
  font-size: 1.3em;
  width: 100px;
  height: 100px;
  margin-right: 10px;
  background: gray;
  z-index: 9;
  cursor: pointer;
  transform: translate(-300px, -50%);
}

#speed {
  transform: translate(200px, -50%);
}
<div class="center" id="speed">Speed</div>
<div class="center" id="brake">Brake</div>
<div class="center round" id="board">
  <div class="center" id="red-bar"></div>
  <div class="center" id="pointer">
    <div class="center round" id="knot"></div>
    <div class="center" id="arm"></div>
  </div>
  <div class="center" id="bars">
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
    <div class="bar center"></div>
  </div>
  <div class="center" id="numbers">
    <div class="num center">0</div>
    <div class="num center">20</div>
    <div class="num center">40</div>
    <div class="num center">60</div>
    <div class="num center">80</div>
    <div class="num center">100</div>
    <div class="num center">120</div>
    <div class="num center">140</div>
    <div class="num center">160</div>
  </div>
  <div class="center" id="mileage">
    <div id="box">31415</div>
    <div id="miles">miles</div>
  </div>
</div>

我从规格中找到了这个,说

For each element with a before-change style and an after-change style, and each property (other than shorthands) for which the before-change style is different from the after-change style, implementations must start transitions based on the relevant item

我在这里解释的是这种情况,您的 #bar before-changenot 不同于 #shrink:hover ~ #bar after-change 值,因此没有过渡开始。

来源:https://www.w3.org/TR/css3-transitions/#starting