禁用从父级继承的伪元素的CSS动画



标题几乎说明了一切,但这里有一个例子。

假设我有一个CSS"加载微调器",如下所示:

.spinner {
    height: 50px;
    width: 50px;
    position: relative;
    animation: rotate .6s infinite linear;
    border-left: 6px solid #222;
    border-right: 6px solid #222;
    border-bottom: 6px solid #222;;
    border-top: 6px solid #ccc;
    border-radius: 100%; 
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}

我想在此添加一个伪元素,例如在.spinner之前或之后添加content: 'loading...'

是否可以确保伪元素不继承.spinner的动画,或者伪元素必须始终继承父元素的动画?

由于伪元素是父元素的子元素,只要父元素有动画,它就会继续旋转。即使在伪元素上设置animation: none也没有效果。

让它看起来像孩子没有动画的唯一方法是反转效果,如下面的片段所示。所做的是将完全相同的动画添加到伪元素,但将animation-direction设置为reverse。这意味着伪得到了精确的反向变换效果,从而将其保持在相同的位置。

.spinner {
  height: 50px;
  width: 50px;
  position: relative;
  animation: rotation .6s infinite linear;
  border-left: 6px solid #222;
  border-right: 6px solid #222;
  border-bottom: 6px solid #222;
  border-top: 6px solid #ccc;
  border-radius: 100%;
}
.spinner:after {
  position: absolute;
  content: 'Loading..';
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  animation: rotation .6s infinite linear reverse; /* added this line */
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}
<div class='spinner'></div>


上面的代码段使用了transform-origin的默认设置,即50% 50%,但如果子伪元素具有padding和/或margin,则必须相应地调整transform-origin设置,以避免伪元素产生类似颤抖的效果。下面的代码段提供了计算逻辑。

.spinner {
  height: 50px;
  width: 50px;
  position: relative;
  animation: rotation .6s infinite linear;
  border-left: 6px solid #222;
  border-right: 6px solid #222;
  border-bottom: 6px solid #222;
  border-top: 6px solid #ccc;
  border-radius: 100%;
}
.spinner.parent-padded-margin {
  padding: 10px;
  margin: 10px;
}
.spinner:after {
  position: absolute;
  content: 'Loading..';
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  animation: rotation .6s infinite linear reverse;
  /* added this line */
}
.spinner.child-padded-margin:after {
  padding: 10px 8px;
  margin: 5px 4px;
  transform-origin: calc(50% - 12px) calc(50% - 15px);  /* calc(50% - ((padding-left + padding-right)/2 + margin-left)) calc(50% - ((padding-top + padding-bottom)/2 + margin-top)) */
}
.spinner.child-padded-margin-2:after {
  padding: 10px 6px 16px 14px;
  margin: 7px 12px 5px 10px;
  transform-origin: calc(50% - 20px) calc(50% - 20px);  /* calc(50% - ((padding-left + padding-right)/2 + margin-left)) calc(50% - ((padding-top + padding-bottom)/2 + margin-top)) */
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}
<div class='spinner'></div>
<div class='spinner parent-padded-margin'></div>
<div class='spinner child-padded-margin'></div>
<div class='spinner child-padded-margin-2'></div>

定位伪元素(使用topleftbottomright)也会影响动画。它还需要相应地修改transform-origin,以便动画正常工作。下面的片段中提供了一个示例。

.spinner {
  height: 50px;
  width: 50px;
  position: relative;
  animation: rotation .6s infinite linear;
  border-left: 6px solid #222;
  border-right: 6px solid #222;
  border-bottom: 6px solid #222;
  border-top: 6px solid #ccc;
  border-radius: 100%;
}
.spinner.parent-padded-margin {
  padding: 10px;
  margin: 10px;
}
.spinner:after {
  position: absolute;
  content: 'Loading..';
  height: 100%;
  width: 100%;
  animation: rotation .6s infinite linear reverse;  /* added this line */
}
.spinner.child-positioned{
    margin-bottom: 40px;
  }
.spinner.child-positioned:after {
  top: 120%;
  left: 2%;
  transform-origin: calc(50% - 2%) calc(50% - 120%); /* basically need to subtract the distance from the left and top of the container */
}
.spinner.child-positioned-negative:after {
  bottom: -120%;
  right: -2%;
  transform-origin: calc(50% - 2%) calc(50% - 120%); /* basically need to subtract the distance from the left and top of the container */
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}
<div class='spinner child-positioned'></div>
<div class='spinner child-positioned-negative'></div>

注意:以上两种解决方案在最新版本的Chrome、Opera和Safari中都能很好地工作,但会导致文本在IE 11、Edge和Firefox中出现倾斜外观。Firefox似乎需要一个单独的动画,从FF的旋转(-10度)到旋转(-370度),而在IE中它变得更加复杂。


在不对pseudo(child)元素设置反向动画的情况下,唯一的替代方法是使用Chris在评论中提到的方法。这意味着将边界和动画直接设置为伪元素。这意味着父对象的内容将不受影响,因为父对象不会受到子对象变换的影响。

.spinner {
  height: 50px;
  width: 50px;
  position: relative;
}
.spinner:after {
  position: absolute;
  content: '';
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  animation: rotation .6s infinite linear;
  border-left: 6px solid #222;
  border-right: 6px solid #222;
  border-bottom: 6px solid #222;
  border-top: 6px solid #ccc;
  border-radius: 100%;
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}
<div class='spinner'>Loading...</div>

为了完整起见,在@Harry给出全面答案的同时,我制作了一个文本位于微调器下方的版本。这样做的方法是使用.spinner作为画布,将实际的旋转圆:beforeloading...放在:after中,如下所示:

.spinner:before {
    content: ' ';
    display: block;
    height: 50px;
    width: 50px;
    margin: 24px auto 6px auto;
    animation: rotation .6s infinite linear;
    border-left: 6px solid #222;
    border-right: 6px solid #222;
    border-bottom: 6px solid #222;;
    border-top: 6px solid #ccc;
    border-radius: 100%;
}
.spinner {
  height: 100px;
  width: 100px;
  position: relative;
}
.spinner:after {
  display: block;
  text-align: center;
  content: 'loading...';
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}
<div class='spinner'></div>

最新更新