Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using FA5 with Turbolinks, fixing flicker? #11924

Closed
excid3 opened this issue Dec 13, 2017 · 20 comments
Closed

Using FA5 with Turbolinks, fixing flicker? #11924

excid3 opened this issue Dec 13, 2017 · 20 comments
Assignees
Milestone

Comments

@excid3
Copy link

excid3 commented Dec 13, 2017

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?

ledermann added a commit to ledermann/docker-rails that referenced this issue Jan 26, 2018
@robmadole
Copy link
Member

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.

@johnclittle
Copy link

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() and turbolinks:before-render since it provides access to the body element prior to rendering? https://github.com/turbolinks/turbolinks#full-list-of-events

@fuchsberger
Copy link

fuchsberger commented Feb 9, 2018

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">

@glebtv
Copy link

glebtv commented Mar 8, 2018

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

  1. Patch fontawesome.js to disable async/requestAnimationFrame here
    var frame = WINDOW.requestAnimationFrame || function (op) {
  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.

@thimo
Copy link

thimo commented Mar 8, 2018

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({.

@glebtv
Copy link

glebtv commented Mar 9, 2018

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)

@jdmb77
Copy link

jdmb77 commented Sep 28, 2018

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!

@pomartel
Copy link

pomartel commented Oct 1, 2018

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.

@jdmb77
Copy link

jdmb77 commented Oct 1, 2018

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.

@robmadole
Copy link
Member

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

@tagliala tagliala added this to the 5.7.0 milestone Mar 6, 2019
@manuelmeurer
Copy link

manuelmeurer commented Mar 7, 2019

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

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

@jprinaldi
Copy link

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

Can somebody else confirm whether this is indeed fixed?

@tagliala tagliala removed this from the 5.7.0 milestone Mar 7, 2019
@tagliala
Copy link
Member

tagliala commented Mar 7, 2019

@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"

@tomkra
Copy link

tomkra commented Mar 7, 2019

@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.

@tagliala
Copy link
Member

tagliala commented Mar 7, 2019

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

@tagliala tagliala reopened this Mar 7, 2019
@robmadole
Copy link
Member

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.

@robmadole
Copy link
Member

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.

@tagliala
Copy link
Member

tagliala commented Mar 20, 2019

I think this has been solved in version 5.8.0

Code: https://github.com/diowa/ruby2-rails5-bootstrap-heroku/blob/422467be1206e2887ec49f71ba2866daf4c477a2/app/javascript/src/fontawesome.js

Relevant configuration line:

config.mutateApproach = 'sync'

Demo: https://ruby2-rails5-bootstrap-heroku.herokuapp.com/

@tagliala tagliala removed the question label Mar 20, 2019
@tagliala tagliala added this to the 5.8.0 milestone Mar 20, 2019
@tagliala
Copy link
Member

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

@tagliala
Copy link
Member

Docs: https://fontawesome.com/how-to-use/on-the-web/using-with/turbolinks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests