Server side rendering icons with Font Awesome
Spencer Miskoviak
September 15, 2019
Photo by Steve Johnson
At some point nearly every app has a need for icons. Font Awesome is one of many options that can fit this need. When first adding Font Awesome to a server side rendered application it's common to notice the icons "flickering" large for a split second.
Why is this happening?
For Font Awesome to work properly, the supporting CSS must exist. This is accomplished by the Font Awesome SVG core package. It dynamically inserts CSS into the head of the HTML document when it's called. For example, when an icon is used it will ensure the CSS has been added.
This works great for a client rendered app because the CSS gets added right before the first icon is rendered. However, with a server side rendered app, the icon already exists in the HTML before the JavaScript bundle has even loaded, let alone before it has been invoked and able to insert the CSS.
The time it takes between the initial HTML rendering and the SVG core package inserts the CSS is the cause of the "flicker." This would likely be more exaggerated on slower networks since the time between the HTML rendering and the script downloading is likely longer.
How is this fixed?
It requires a little bit of additional work but fortunately Font Awesome provides all of the necessary APIs to server render icons and avoid the "flicker" caused by the dynamic injection of CSS. To solve this problem, the gap between the icons rendering and the CSS being added needs to be removed. But how?
The initial render on the server needs to respond with this CSS already inlined.
This can be done using the dom.css()
method. The following is an example of an HTML
component that will
be rendered using renderToStaticMarkup
.
// server-side rendered component
import { dom } from "@fortawesome/fontawesome-svg-core";
const HTML = () => (
<html>
<head>
// other links, styles,etc.
<style type="text/css">{dom.css()}</style>
</head>
<body>{/* server rendered content */}</body>
</html>
);
In the initial HTML response the style tag with the Font Awesome specific styles should now be visible.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
svg:not(:root).svg-inline--fa {
overflow: visible;
}
/* And a bunch more styles... */
</style>
</head>
<body>
/* server rendered content */
</body>
</html>
However, if you inspect the DOM after the client has loaded, there are
two duplicate style
tags with the same Font Awesome styles.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
svg:not(:root).svg-inline--fa {
overflow: visible;
}
/* And a bunch more styles... */
</style>
<style type="text/css">
svg:not(:root).svg-inline--fa {
overflow: visible;
}
/* And a bunch more styles... */
</style>
</head>
<body>
<!-- server rendered content -->
</body>
</html>
Why is this happening? The styles are manually added on the server. This
fixes the large "flickering" since the CSS is immediately available, However, the
client is also still injecting the styles once it has loaded. There is also the
autoAddCss
configuration option available to disable this.
// client entry point file
import React from "react";
import ReactDOM from "react-dom";
import { config } from "@fortawesome/fontawesome-svg-core";
import App from "../shared/app";
// Disable the automatic insertion
// of CSS into the head of the document.
config.autoAddCss = false;
const root = document.getElementById("root");
ReactDOM.hydrate(<App />, root);
An animated GIF would be included like above but it would appear to be a still screenshot now that the flicker is fixed.
Conclusion
Now, the required Font Awesome styles are immediately available because the
initial server response inlines them in the head
of the document. Additionally,
the duplicate addition of styles is fixed by disabling that behavior on the client.
As with most packages, server side rendering introduced additional overhead and complexity but it's a tradeoff for other benefits such as a potential for more performant first paints or improved SEO.
The full code for a simple server side rendering React app with Font Awesome is available here.
Tags:
course
Practical Abstract Syntax Trees
Learn the fundamentals of abstract syntax trees, what they are, how they work, and dive into several practical use cases of abstract syntax trees to maintain a JavaScript codebase.
Check out the course