Font-awesome: Using FA5 with Turbolinks, fixing flicker?

Created on 13 Dec 2017  路  20Comments  路  Source: FortAwesome/Font-Awesome

Turbolinks compatibility is something I'd love to have with the SVG version of FA5. Right now, I have hacked together a solution that works alright, but each new pageview flickers with the icons being rendered and I was curious if there'd be a smoother way for handling this.

  1. Include Turbolinks
  2. Include svg-with-js library for FA5
  3. Add the following to re-run FA5 each new Turbolinks pageview
document.addEventListener("turbolinks:load", function() {
  FontAwesome.dom.i2svg();
});

This works well, but produces a noticeable flicker going back and forth between pages while the Javascript replaces tags on the page with their SVG equivalents.

Is there any better way we can do this?

enhancement

Most helpful comment

This can easily be fixed through a config that attaches the mutation observer to the document instead of the body.

FontAwesome.dom.watch({observeMutationsRoot: document})

https://fontawesome.com/how-to-use/with-the-api/methods/dom-watch

Then there's no need to use turbolinks events or trigger the i2svg method.

Awesome!! Thanks so much @pomartel. Now I don't have to declare this in every case statement.

All 20 comments

Ok, folks. This has come up enough that I'll see if I can help out.

The flicker can be controlled best through CSS. Here are some docs: https://fontawesome.com/how-to-use/performance-and-security#async-loading-indicators

Another option is to leverage the callback that i2svg() has. https://fontawesome.com/how-to-use/font-awesome-api#dom-i2svg

You could do something like:

document.addEventListener("turbolinks:load", function() {
  // do something to hide everything
  FontAwesome.dom.i2svg({
    callback: function () {
      // do something to show everything
    }
  });
});

Do either of those options help? I will add something to our docs if it does.

body {
  display: none;
}

.fontawesome-i2svg-active body {
  display: block;
}

Unfortunately for me the above as suggested at https://fontawesome.com/how-to-use/performance-and-security#async-loading-indicators makes the whole page flicker.

My understanding is that turbolinks:load fires after it renders the page. Is there anyway to leverage i2svg() andturbolinks:before-render since it provides access to the body element prior to rendering? https://github.com/turbolinks/turbolinks#full-list-of-events

to avoid flickering you can just use the Webfonts with CSS version for now:

In <head> add:

<link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet">

Here's a dirty, hacky way to get zero flicker with turbolinks

  1. Patch fontawesome.js to disable async/requestAnimationFrame here
    https://github.com/FortAwesome/Font-Awesome/blob/31281606f5205b0191c17c3b4d2d56e1ddbb2dc6/svg-with-js/js/fontawesome.js#L866
  2. Use this code
document.addEventListener("turbolinks:before-render", function(event) {
  FontAwesome.dom.i2svg({
    node: event.data.newBody
  });
});

Works for me, no flicker.

Proper way to solve this would be for fontawesome.js to provide a synchronius alternative\option for dom.i2svg for use cases like this.

That's great, works for me as well. The patch on fontawesome.js involves removing WINDOW.requestAnimationFrame || (right?) and I had to proper-case fontawesome.dom.i2svg({ to FontAwesome.dom.i2svg({.

yes, just comment out frame(function () { and });, not what's inside it
This is probably not a perfect (or even good) solution since this is also called in DOM mutation observers, so any dynamic changes to the page might be slow
this seems to be possible to disable, like so

FontAwesome.config = {
  observeMutations: false,
}

(fixed case - this was my import name)

Turbolinks compatibility is something I'd love to have with the SVG version of FA5. Right now, I have hacked together a solution that works alright, but each new pageview flickers with the icons being rendered and I was curious if there'd be a smoother way for handling this.

  1. Include Turbolinks
  2. Include svg-with-js library for FA5
  3. Add the following to re-run FA5 each new Turbolinks pageview
document.addEventListener("turbolinks:load", function() {
  FontAwesome.dom.i2svg();
});

This works well, but produces a noticeable flicker going back and forth between pages while the Javascript replaces tags on the page with their SVG equivalents.

Is there any better way we can do this?

This worked like a charm when using jQuery load() to dynamically load a Rails 5 view into a section of the page. Icons would load fine on plain HTML pages, but when loading a html.erb view it would not load the icons. Placed the FontAwesome.dom.i2svg(); in the jQuery load complete and works every time. Thanks for the post @excid3!

This can easily be fixed through a config that attaches the mutation observer to the document instead of the body.

FontAwesome.dom.watch({observeMutationsRoot: document})

https://fontawesome.com/how-to-use/with-the-api/methods/dom-watch

Then there's no need to use turbolinks events or trigger the i2svg method.

This can easily be fixed through a config that attaches the mutation observer to the document instead of the body.

FontAwesome.dom.watch({observeMutationsRoot: document})

https://fontawesome.com/how-to-use/with-the-api/methods/dom-watch

Then there's no need to use turbolinks events or trigger the i2svg method.

Awesome!! Thanks so much @pomartel. Now I don't have to declare this in every case statement.

We've changed the default watch target to document now. So this should be fixed.

Thanks, @robmadole! Is this included in v5.7.2?

EDIT: Nevermind, I see it was changed in 5.7.0. 馃槃

I tried updating to v5.7.2 and I still experience the same issue.

Can somebody else confirm whether this is indeed fixed?

@juampi same here.

I think this issue is not the same as the one fixed in 5.7.0, for turbolinks compatibility out of the box

However, I do not know if there is a solution for the flicker

How to replicate:

  1. Navigate to https://ruby2-rails5-bootstrap-heroku.herokuapp.com/
  2. Go back and forward between "Hello World" and "Rails 5 starter app"

@tagliala There is a solution. When you remove this piece of code WINDOW.requestAnimationFrame || from all.js, flicker with turbolinks will disappear. I'm using this solution in my gem with no visible side effects.

Maybe someone from FortAwesome could explain us what's the purpose of this code in all.js and help with turbolinks flickering problem to get fixed out of the box.

When you remove this piece of code WINDOW.requestAnimationFrame || from all.js, flicker with turbolinks will disappear.

Thanks!

what's the purpose of this code in all.js

I'm pretty confident that there is a reason, but I do not know what it is 馃槄

Let's wait for some other feedback from @robmadole

Meanwhile, I'm reopening here

The requestAnimationFrame code is there to improve performance. (Or to schedule the changes for icon replacements when it's convenient for the browser). It separates the changes that are needed from the changes occurring. This keeps the "jank" at a minimum as we render icons.

While this works pretty well in most cases I can understand this asynchronous operation creates a flash of changing content for Turbolinks. So, the best way to address this is add a configuration option that forces these operations (the mutations to the DOM) to be performed immediately.

Let me take a look at how much effort this is going to be.

Alright, this wasn't difficult to implement and we'll have a new config option that can control how the engine replaces icons. This will be included in 5.8.0.

I'm going to close here, feel free to comment if something is still wrong

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sezeresen picture sezeresen  路  3Comments

lickmydesign picture lickmydesign  路  3Comments

seppestas picture seppestas  路  3Comments

huuphat picture huuphat  路  3Comments

rufengch picture rufengch  路  3Comments