CSS3 animations don't always run when 'display' attribute is set on a pseudo element

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 <strong>not</strong> 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:

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/uf6pd.gif" alt="When it works">

When it doesn't work:

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/zTzkB.gif" alt="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:

<ol> <li><strong>Works in:</strong>
    <li>Mac OS X 10.10.5
      <li>Chrome 47.0.2526.111</li> </ul></li> <li>Windows 10.0.10240
        <li>IE 11.0.10240.16644</li> <li>Edge 10.10240.16384.0</li> </ul></li> </ul></li> <li><strong>Doesn't work in:</strong>
          <li>Mac OS X 10.10.5
            <li>Chrome Canary 50.0.2639.0 (!!)</li> <li>Safari 9.0.3 (10601.4.4)</li> <li>Firefox 44.0</li> </ul></li> <li>Windows 10.0.10240
              <li>Chrome 48.0.2564.97</li> <li>Firefox 44.0</li> </ul></li> </ul></li> </ol>

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


              <strong>Why does the animation not work when fa-before class is applied?</strong>

              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.

              <strong>transformable element</strong>

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

              <strong>atomic inline-level element</strong>

              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.


              <strong>What is the solution?</strong>

              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 */

              <sup><strong>Note:</strong> 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.</sup>


              <strong>Why does it work on some browsers?</strong>

              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.


              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 - <strong>JSFiddle</strong>


  • Click a checkbox with selenium-webdriver
  • Catch change event on input field dynamically added to Jquery Datatables table
  • AND selector jQuery
  • Convert a 12 hour time format to 24 hour time format (keeping record of the day) in python
  • Packet modification with netfilter queue?
  • PHP file_exists() anomaly
  • Can I use Jquery to automatically find and set the width and height of a variety of images?
  • How can I let users share their location in Bot Framework webchat channel?
  • PayPal API Listener Website Payments Standard URI
  • HttpURLConnection Closing IO Streams
  • How to 'create temp table as select' in Slick?
  • Repository Browser Only - \"Repository moved permanently to… please relocate”
  • Hide HTML elements without javascript, only CSS
  • Web.config system.webserver errors
  • Parsing a CSV string while ignoring commas inside the individual columns
  • Why value captured by reference in lambda is broken? [duplicate]
  • Jenkins: How To Build multiple projects from a TFS repository?
  • What is Eclipse's Declaration View used for?
  • Sony Xperia Z Tablet not found by adb
  • How to recover from a Spring Social ExpiredAuthorizationException
  • ILMerge & Keep Assembly Name
  • Javascript convert timezone issue
  • How to make Safari send if-modified-since header?
  • Large data - storage and query
  • How can I estimate amount of memory left with calling System.gc()?
  • Jquery - Jquery Wysiwyg return html as a string
  • Function pointer “assignment from incompatible pointer type” only when using vararg ellipsis
  • WOWZA + RTMP + HTML5 Playback?
  • 0x202A in filename: Why?
  • SVN: Merging two branches together
  • How to set the response of a form post action to a iframe source?
  • Hits per day in Google Big Query
  • Why joiner is not used after Sequence generator or Update statergy
  • Change div Background jquery
  • File not found error Google Drive API
  • Qt: Run a script BEFORE make
  • Append folder name and increment by 1 using batch script
  • Recursive/Hierarchical Query Using Postgres
  • reshape alternating columns in less time and using less memory
  • UserPrincipal.Current returns apppool on IIS