悬停旋转元素时的怪异行为

时间:2018-10-01 10:49:58

标签: css css3 css-transitions css-transforms

给出这两个例子。

使用悬停

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: var(--top);
  transition: transform 2s;
  transform: translateX(-50%);
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
}

div:hover {
  transform: translateX(-50%) rotate(var(--deg));
}

div:nth-child(1) {
  --deg: 180deg;
  --top: 20%;
}

div:nth-child(2) {
  --deg: -180deg;
  --top: 40%;
}

div:nth-child(3) {
  --deg: 360deg;
  --top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>


使用动画

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: var(--top);
  transform: translateX(-50%);
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
  animation: rotate 2s linear 2s;
}

@keyframes rotate {
  to {
    transform: translateX(-50%) rotate(var(--deg));
  }
}

div:nth-child(1) {
  --deg: 180deg;
  --top: 20%;
}

div:nth-child(2) {
  --deg: -180deg;
  --top: 40%;
}

div:nth-child(3) {
  --deg: 360deg;
  --top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>


您可以看到rotate(180deg)rotate(-180deg)的行为相同,而rotate(360deg)完全不动。

问题是,如果您让它逐渐移动,它就会正常工作。

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
}

div:hover {
  animation: rotate 2s linear;
}

@keyframes rotate {
  0% {
    transform: translate(-50%, -50%) rotate(0deg);
  }
  25% {
    transform: translate(-50%, -50%) rotate(45deg);
  }
  50% {
    transform: translate(-50%, -50%) rotate(90deg);
  }
  75% {
    transform: translate(-50%, -50%) rotate(135deg);
  }
  100% {
    transform: translate(-50%, -50%) rotate(180deg);
  }
}
<div></div>

我发现的解决方案是用不一致的translate(-50%, -50%)替换margins

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: var(--top);
  transition: transform 2s;
  /* Minus half the width, hard coded not a good idea*/
  margin: 0 0 0 -75px; 
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
}

div:hover {
  transform: rotate(var(--deg));
}

div:nth-child(1) {
  --deg: 180deg;
  --top: 20%;
}

div:nth-child(2) {
  --deg: -180deg;
  --top: 40%;
}

div:nth-child(3) {
  --deg: 360deg;
  --top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>

所以主要问题是为什么会发生这种奇怪的行为?

编辑:不只是寻找快速答案(您可以看到有两个可用的答案),而且还有一个解释:)

2 个答案:

答案 0 :(得分:1)

您需要设置一个初始rotate(0),以便在两个状态之间可以设置动画。将div的初始转换设置为:

transform: translateX(-50%) rotate(0);

转换:

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: var(--top);
  transition: transform 2s;
  transform: translateX(-50%) rotate(0);
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
}

div:hover {
  transform: translateX(-50%) rotate(var(--deg));
}

div:nth-child(1) {
  --deg: 180deg;
  --top: 20%;
}

div:nth-child(2) {
  --deg: -180deg;
  --top: 40%;
}

div:nth-child(3) {
  --deg: 360deg;
  --top: 60%;
}

body {
  overflow: hidden;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>

动画:

div {
  position: absolute;
  width: 150px;
  height: 40px;
  background: orange;
  left: 50%;
  top: var(--top);
  transform: translateX(-50%) rotate(0);
  text-align: center;
  line-height: 40px;
  font-size: 1.2em;
  animation: rotate 2s linear 2s forwards;
}

@keyframes rotate {
  to {
    transform: translateX(-50%) rotate(var(--deg));
  }
}

div:nth-child(1) {
  --deg: 180deg;
  --top: 20%;
}

div:nth-child(2) {
  --deg: -180deg;
  --top: 40%;
}

div:nth-child(3) {
  --deg: 360deg;
  --top: 60%;
}

body {
  overflow: hidden;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>

答案 1 :(得分:0)

如果您尝试在Firefox上运行代码,则似乎是浏览器错误(至少在Chrome上如此),因为它可以正常运行。

请参考 the specification进行解释。这是变换之间的插值应如何工作的所有不同情况。

enter image description here

在我们的情况下,我们将考虑没有相同数量的转换函数的最后一点,浏览器应通过从缺失列表中添加标识转换函数来处理此问题,在我们的情况下,应为{{ 1}}。

从技术上讲,从rotate(0)translate(-50%)的过渡应该与从translate(-50%) rotate(360deg)translate(-50%) rotate(0)的过渡相同。

除非我缺少某种可以肯定的错误,例如单独使用translate(-50%) rotate(360deg)时,Chrome会使用第二点(当一个值为rotate(360deg)时)很好地解决了这一问题与最后一点几乎相同。