CSS3 animations don't always run when 'dis

2019-07-15 06:03发布

The problem I am running into occurs when trying to animate a web font. Specifically, if the HTML element has a class that defines the font-family and other needed CSS attributes on the :before element as opposed to the element itself, the pseudo content will not get animated.

Here is some sample CSS:

@font-face {
  font-family: 'FontAwesome';
  src: /** src urls here... **/
}

.fa-before:before,
.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-refresh:before {
  content: "\f021";
}

.spinning-loader {
  -webkit-animation: fa-spin 2s infinite linear;
  animation: fa-spin 2s infinite linear;
}

@-webkit-keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}
@keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}

Now the key part is my fa and fa-before:before selectors.

If I use the fa-before class, that works fine to set the correct font-family of my :before content. Additionally, plain fa also works fine for the :before content (and I think any other content too).

The problem is, if an element has fa-before, it doesn't animate (at least, not all browsers animate it).

<!-- This doesn't always animate -->
<i class="fa-before icon-refresh spinning-loader"></i>

<!-- This DOES always animate -->
<i class="fa icon-refresh spinning-loader"></i> 

When it works:

When it works

When it doesn't work:

When it doesn't work

Here is a JSFiddle so you can test in your own browser: https://jsfiddle.net/b3gojahs/1/

Here are all the browsers I've been able to test:

  1. Works in:
    • Mac OS X 10.10.5
      • Chrome 47.0.2526.111
    • Windows 10.0.10240
      • IE 11.0.10240.16644
      • Edge 10.10240.16384.0
  2. Doesn't work in:
    • Mac OS X 10.10.5
      • Chrome Canary 50.0.2639.0 (!!)
      • Safari 9.0.3 (10601.4.4)
      • Firefox 44.0
    • Windows 10.0.10240
      • Chrome 48.0.2564.97
      • Firefox 44.0

Anyone know why this is occurring? I can't seem to find any articles on this issue.

2条回答
你好瞎i
2楼-- · 2019-07-15 07:01

The issue seems to be setting the

.fa-before:before{
  display: inline-block;
}

Is you just make this

.fa-before {
  display: inline-block;
}

It works just fine - JSFiddle

查看更多
ら.Afraid
3楼-- · 2019-07-15 07:07

Why does the animation not work when fa-before class is applied?

The problem is because i element is an inline element by default and CSS transforms don't work on inline elements. Inline elements are not transformable elements.

As per W3C Spec:

Transforms apply to transformable elements.

transformable element

A transformable element is an element in one of these categories: an element whose layout is governed by the CSS box model which is either a block-level or atomic inline-level element, or whose display property computes to table-row, table-row-group, table-header-group, table-footer-group, table-cell, or table-caption [CSS21]

atomic inline-level element

Inline-level boxes that are not inline boxes (such as replaced inline-level elements, inline-block elements, and inline-table elements) are called atomic inline-level boxes because they participate in their inline formatting context as a single opaque box.

When the fa class is applied on the element, the element's display is changed to inline-block via the CSS and so the animation that is applied through .spinning-loader selector works as expected.

However when the fa-before class is applied on the element, only the :before pseudo-element of the i gets the display changed to inline-block. The display setting of the i itself doesn't change and it remains as the default inline setting. Because of this, the animation on the i has no effect.


What is the solution?

Solution is exactly the same that is mentioned in Paulie_D's answer. The parent i element on which the transform animation is applied should be made as a block or an inline-block element.

i.spinning-loader {display: inline-block;} /* this setting should solve it */

Note: The behavior in Chrome is a bit erratic (atleast on my PC - v43 + Win 7). It starts working automatically when I make any change to the fiddle, close and then reopen it. I have no explanation for this but Firefox is perfect.


Why does it work on some browsers?

This is something to which I don't have an answer at present. The only reason could be that they treat the i element differently and set its default display setting as block or inline-block.

查看更多
登录 后发表回答