【问题标题】:CSS3 animation doesn't work if div:before is floating (WebKit)如果 div:before 是浮动的 (WebKit),CSS3 动画将不起作用
【发布时间】:2023-03-07 15:42:01
【问题描述】:

我希望我的文本仅使用 CSS3 闪烁。它工作正常。但是,如果我将 float:left 添加到 div 的 :before 选择器中,它会阻止动画在 WebKit (Safari/Chrome) 上运行。

为了演示,请在 WebKit 上打开 JSFiddle,删除 float:left 以查看它是否正常工作。

CSS:

.blink_me:before {
  content: "Blink";
}

.blink_me {
  -webkit-animation: blinker 1.5s linear infinite;
  -moz-animation: blinker 1.5s linear infinite;
  -o-animation: blinker 1.5s linear infinite;
  animation: blinker 1.5s linear infinite; 
}
@keyframes blinker {  
  50% { opacity: 0.0; }
}

HTML:

<span class="blink_me"> </span>

如何使它与选择器上的浮动一起使用?

BOUNTY 信息:只是奖励一个肯定值得更多支持的现有答案。

【问题讨论】:

  • 我可以确认它适用于 FF,但不适用于 webkit。有趣的问题。 +1
  • 添加位置:相对于伪选择器。不幸的是,我无法提供更多信息:D
  • @Tonsenson 这并没有恭敬地回答这个问题。如果您无法提供更多信息,为什么还要发表评论? :)
  • 只是因为我不明白这是如何解决它的,也许阅读我评论的人可以解释它并减轻我们的负担:)

标签: css webkit css-animations


【解决方案1】:

原因:

这肯定是因为 Webkit 中的层创建和加速渲染过程。在开发工具中启用“显示绘制矩形”和“显示复合层边框”选项后,查看此答案中的所有演示。

运行任何一个演示时,您都会看到一些绿色和橙色框。绿色框是绘制矩形,而橙色框是渲染引擎为加速渲染而创建的合成层。在渲染过程中,Webkit(和 Blink)并不总是重新绘制整个页面。只有页面的受影响区域(层)被重新绘制(为了性能)。

带浮点数:

在这个 sn-p 中,您会看到渲染引擎创建了一个绘制矩形、一个页面合成层和一个绘制矩形、span 元素(“某些内容”)的合成层。由于spaninline 元素,它不会生成包含其后代框和生成内容的principal block-level box。这(根据我的理解)使伪元素相对于根元素浮动。这也意味着伪元素在屏幕上的位置不依赖于父 span 元素(事实上,如果你给 span 一个负边距,你会注意到内容重叠,而如果为span 设置负边距将伪元素的内容也向左移动)。由于浮动元素的状态不会影响跨度,并且由于它也没有自己的合成层,因此动画不会改变其不透明度。

.blink_me:before {
  content: "Blink";
  float: left;
}
.blink_me {
  -webkit-animation: blinker 1.5s linear infinite;
  -moz-animation: blinker 1.5s linear infinite;
  -o-animation: blinker 1.5s linear infinite;
  animation: blinker 1.5s linear infinite;
}
@keyframes blinker {
  50% {
    opacity: 0.0;
  }
}
&lt;span class="blink_me"&gt;Some content&lt;/span&gt;

没有浮动:

这里引擎还创建了两个图层 + 两个绘制矩形,但由于没有浮动,伪元素也是 inline 并且是父元素 span 的一部分(你会看到一个框覆盖“闪烁”和“一些内容”)。现在由于伪元素的内容也是父图层的一部分,所以父元素上的动画也会影响伪元素的内容。

.blink_me:before {
  content: "Blink";
}
.blink_me {
  -webkit-animation: blinker 1.5s linear infinite;
  -moz-animation: blinker 1.5s linear infinite;
  -o-animation: blinker 1.5s linear infinite;
  animation: blinker 1.5s linear infinite;
}
@keyframes blinker {
  50% {
    opacity: 0.0;
  }
}
&lt;span class="blink_me"&gt;Some content&lt;/span&gt;

解决方案:

执行以下任一操作都会导致伪元素的内容被视为父元素层的一部分,因此父元素上的动画也会影响子元素。当应用这些设置中的任何一个时,您会再次注意到覆盖 span 元素内容和伪元素内容的橙色边框。

  • 在伪元素(相对或绝对甚至固定)上设置任何position

    .blink_me:before {
      content: "Blink";
      float: left;
      position: relative;
    }
    .blink_me {
      -webkit-animation: blinker 1.5s linear infinite;
      -moz-animation: blinker 1.5s linear infinite;
      -o-animation: blinker 1.5s linear infinite;
      animation: blinker 1.5s linear infinite;
    }
    @keyframes blinker {
      50% {
        opacity: 0.0;
      }
    }
    &lt;span class="blink_me"&gt;Some content&lt;/span&gt;
  • 在伪元素上设置除 1 以外的 opacity(如 0.99 等)。

    .blink_me:before {
      content: "Blink";
      float: left;
      opacity: 0.99;
    }
    .blink_me {
      -webkit-animation: blinker 1.5s linear infinite;
      -moz-animation: blinker 1.5s linear infinite;
      -o-animation: blinker 1.5s linear infinite;
      animation: blinker 1.5s linear infinite;
    }
    @keyframes blinker {
      50% {
        opacity: 0.0;
      }
    }
    &lt;span class="blink_me"&gt;Some content&lt;/span&gt;
  • 在伪元素上设置transform: translateZ(0px);

    .blink_me:before {
      content: "Blink";
      float: left;
      transform: translateZ(0px);
    }
    .blink_me {
      -webkit-animation: blinker 1.5s linear infinite;
      -moz-animation: blinker 1.5s linear infinite;
      -o-animation: blinker 1.5s linear infinite;
      animation: blinker 1.5s linear infinite;
    }
    @keyframes blinker {
      50% {
        opacity: 0.0;
      }
    }
    &lt;span class="blink_me"&gt;Some content&lt;/span&gt;

或者,另一种解决方案是直接在伪元素上设置动画,因为它会获得自己的合成层,并且只有该层会受到影响。

.blink_me:before {
  content: "Blink";
  float: left;
  -webkit-animation: blinker 1.5s linear infinite;
  -moz-animation: blinker 1.5s linear infinite;
  -o-animation: blinker 1.5s linear infinite;
  animation: blinker 1.5s linear infinite;
}
@keyframes blinker {
  50% {
    opacity: 0.0;
  }
}
&lt;span class="blink_me"&gt; &lt;/span&gt;

另一个可行的选项是将display 设置为inline-blockblock 到父span。这也使得伪元素成为父元素合成层的一部分,因此它也受到动画的影响。

.blink_me:before {
  content: "Blink";
  float: left;
}
.blink_me {
  display: inline-block;
  -webkit-animation: blinker 1.5s linear infinite;
  -moz-animation: blinker 1.5s linear infinite;
  -o-animation: blinker 1.5s linear infinite;
  animation: blinker 1.5s linear infinite;
}
@keyframes blinker {
  50% {
    opacity: 0.0;
  }
}
&lt;span class="blink_me"&gt; &lt;/span&gt;

总结

在 References 下提供的第二个链接中,您将看到渲染过程在 WebKit(和 Blink)中是如何工作的,从节点到渲染对象到渲染层再到合成层。

以下是这些如何应用于此答案中所有演示的摘要,以及为什么它使每个演示都以它们的方式工作。

当伪元素上没有浮动时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | No           | N/A

这里span 在动画开始时立即获得一个渲染层,因为它是半透明的(由于不透明),并且它获得了一个合成层,因为它具有不透明动画。伪类没有自己的渲染层,因为它不满足任何要求的标准,因此也没有合成层。它成为第一个祖先的渲染+合成层的一部分。在合成过程中,pseudo 的内容也会受到影响,因为它也是 layer 的一部分。

当伪元素上有浮动时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | No           | N/A

与之前相同,但由于有一个浮点数并且它不是span 的一部分,因此伪不是其合成层的一部分,因此在合成操作期间不会被修改。

定位伪元素时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | Yes          | No

当 psuedo 被定位时,它会获得一个自己的渲染层(因为它符合标准),但没有获得合成层,因为它不符合所需的标准。此外,它的定位意味着它在屏幕上的位置会受到跨度上的任何变换的影响。看起来这使得伪元素也成为 span 合成层的一部分,因此被修改为合成操作的一部分。

当伪元素的不透明度小于1时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | Yes          | No

与前一种情况类似。这里不透明度小于1的伪意味着当它下面的层发生变化时它需要改变(否则透明度会被破坏)。因此,这似乎被移到了合成层,因此在合成过程中被修改了。

当伪元素有变换时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | Yes          | Yes

这里,pseudo 也有自己的合成层,因为它上面有一个 3D 变换,并且因为它是 span 的子级,所以它的层在 span 的层之上。这意味着在合成过程中,span 和伪元素的图层都会被修改,因此动画也会影响这里的伪。

伪元素直接动画时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | No           | N/A
:before | Yes   | Yes           | Yes          | Yes

这里,span 没有渲染或合成层,因为不透明动画位于伪元素上。由于 pseudo 有自己的合成层,所以它在合成过程中也会受到影响。

当 span 显示为块或内联块时:

Element | Node  | Render Object | Render Layer | Compositing Layer
-----------------------------------------------------------------------------------------
Root    | Yes   | Yes           | Yes          | Yes (Descendant is a compositing layer)
span    | Yes   | Yes           | Yes          | Yes
:before | Yes   | Yes           | No           | N/A

这与伪元素浮动的情况非常相似,但由于此处的 span 是块级元素,因此它会为其后代生成主要块级框并生成内容。因此,pseudo 成为 span 合成层的一部分,因此在合成过程中受到影响。

注意:整个渲染过程非常复杂,您可以从参考链接中看到,我已尽力解释该过程。我可能有一些错综复杂的细节是错误的,但总的来说,你会发现解释与开发工具的输出相符。


参考资料:

您可以通过以下链接找到有关如何启用“显示绘制矩形”、“显示复合图层边框”选项以及加速渲染过程如何工作的更多信息:

【讨论】:

  • 非常感谢我的朋友。虽然它没有直接回答这个问题,但它确实提供了一个真正的解决方案。一会儿就接受。
  • @HenrikPetterson:是的,我很乐意给你一个直接的答案(我正在努力)。不要接受答案,至少在几个小时内不要接受,因为接受答案的问题获得的观看次数较少,可能会推迟潜在的回答者。
  • 是的,这可能与@HenrikPetterson 相关,但我发现这个问题不仅仅发生在伪元素上。即使我们在显示为内联的父元素中浮动子元素也会发生这种情况。更有趣的是,子/伪元素上的position: relative 也解决了这个问题(正如 cmets 所指出的那样)。
  • 浮动的:before是一个自己的盒子。如果你用 float 检查元素,:before 是一个盒子,span 是一个自己的盒子!动画不会影响浮动的:before,但其他属性如color 正在工作。那很奇怪。小演示:jsfiddle.net/umz8t/5304
  • 不,我只是在等待这个问题有资格获得赏金,以便我可以奖励你出色的答案。谢谢你的一切!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-09
  • 2016-12-18
  • 1970-01-01
相关资源
最近更新 更多