Case Study: FOUC on Firefox
The flash of unstyled content (FOUC) caught my attention for the first time when I was developing the theme for my personal website. Despite being a rare occurence, it was annoying enough that I decided to dive into it a little bit. The investigation specifically focused on Firefox, the only browser I observed the issue on.
What is FOUC?
The term FOUC refers to the scenario when a browser initially displays the webpage in the browser’s default stylesheet; and within a split-second, it applies the proper website’s requested stylesheets to the elements (Here is an example). On Firefox it is accompanied by a warning message on the console: “Layout was forced before the page was fully loaded. If stylesheets are not yet loaded this may cause a flash of unstyled content.”
Why does it happen?
The FOUC is caused by the “late” arrival of stylesheets. Certain browser engines make their own decisions on what is considered “late”.
When a webpage is requested, the browser fetches and parses the HTML. During which, when a browser engine encounters an external stylesheet, it has to decide whether to “stall” or “not to stall” the processing of remaining elements. If the browser decides not to stall on a resource, it might render some elements based on a temporary measures, and later on, correct it when it receives sufficient stylesheet information; that act results in the sudden switch of layouts referred to as the flash. 1
Chris Harrelson made a compilcation of Stylesheet Loading Behavior
accross browsers. Here is an excerpt related to Gecko,
the engine behind Firefox:
“Gecko blocks Painting DOM Elements on obtaining external style sheets
declared as a descendant of <head>
,
except for those declared via @import within another style sheet.”.
His repository also provides strategies to avoid FOUC; however my later experiments
told me that they do not guarantee the absence of the FOUC;
and there is another character in the story.
Firefox Profiler shed more lights on the matter. The visualization below clearly demonstrates that the First Contentful Paint (FCP) had happened before the external stylesheet was completely downloaded. That means stylesheets might not be “render-blocking” on Firefox like one might have mistaken.
Further investigations led me to the conclusion that linked stylesheets
are indeed render-blocking on Firefox under a time limit.
The option nglayout.initialpaint.delay
decides how long the engine is allowed to finish the initial layouts
before it starts painting to the screen.
This option can be accessed in the browser
Configuration Editor.
Since Firefox 53, its default value was
reduced
from 250ms to 5ms. 2
It means the main culprit of the “flash” I have seen on my Firefox browser is actually network latency.
How to avoid FOUC?
While web visitors who use Firefox, can adjust the configuration of
nglayout.initialpaint.delay
at wills if they consistently suffer from
the FOUC, this behaviour leaves web owners with limited choices to
completely avoid the FOUC for every visitors of the websites.
The theoretical way is to embed or inline critical style rules in the HTML, which usually referred to as the “above the fold”. This makes these rules available to the browser immediately. In other words, it eliminates the impact of network latency on the outcome of the initial paint. However, the extraction of “critical CSS” adds a burden to maintainability, and (in some cases) discards the advantage of caching.
A trick/work-around widely suggested on the internet is to explicitly
postpone the painting of the DOM until the stylesheets are ready. For example,
by having a script
block somewhere before the body
elements;
or by initially hide the content, then toggle its visibility when appropriate.
The above are the only methods I am aware of that, by design, would be able to completely prevent the FOUC on Firefox regardless of other factors that are less in the site’s owners controls such as network latency and cache’s availability.
Conclusion
The general idea to avoid layout shifts is to feed the browser engines with sufficient instructions early on so that the engines can effectively plan and execute the rendering. Optimize resources loading helps lower the chance of layout shifts in general.
On Firefox, FOUC can still occur for a relatively well-optimized resources loading strategy if the fact that stylesheets are not completely render-blocking is not taken into accounts. Having said that such FOUC is not something people see regularly, especially after caching has been established. It is interesting to investigate, however whether it’s worth fixing is left for the site owner to decide.
The FOUC Problem (2006) by Dave Hyatt ↩︎
Is it possible that a higher threshold can lower the impact of network latency, and still be responsive to the users? How long is too long? ↩︎