How to stop FOUC when using css loaded by webpack
ExtractTextWebpackPlugin will allow you to output your CSS as a separate file rather than having it embedded in your JS bundle. You can then include this file in your HTML, which as you said, prevents the flash of unstyled content.
I'd recommend only using this in production environments, as it stops hot-loading from working and makes your compile take longer. I have my webpack.config.js
set up to only apply the plugin when process.env.NODE_ENV === "production"
; you still get the FOUC when you're doing a development build/running the dev server, but I feel like this is a fair trade off.
For more information on how to set this up, take a look at SurviveJS's guide.
Update: As noted in the comments, ExtractTextWebpackPlugin has now been superceded by mini-css-extract-plugin - you should use that instead.
Struggling to remove FOUC (Flash Of Unstyled Content) when using Webpack
Right now your styles are baked into the JS files. In your case, the browser takes a while to parse the javascript and only after processing it can apply the styles to the page. That is causing the FOUC.
To cope with this problem ExtractTextPlugin was developed. Basically what it does is it takes out the css specified and puts it in a separate css file. A basic configuration would look like:
const plugin = new ExtractTextPlugin({
filename: '[name].[contenthash:8].css',
});
module: {
rules: [ {
test: /\.css$/,
use: plugin.extract({
use: 'css-loader',
fallback: 'style-loader',
})
}]
},
plugins: [ plugin ]
Then you must attach the generated file to your HTML page if you're not using html-webpack-plugin. By linking generated file in section you will get rid of FOUC.
Flash of unstyled content with react and scss
The problem wasn't because of Webpack. It was because of me being stupid :)
I imported the CSS file inside of a child component, so when I reload the page, it first shows the layout without any styles and then loads the child component and gives the layout a proper style. So basically, the only thing I did to fix the problem was to import the style in the layout component.
import '../style.scsc'
How to resolve FOUC in React.js
FOUC
FOUC - so called Flash of Unstyled Content can be as very problematic as so many tries of solving this issue.
To the point
Let's consider following configuration of routing (react-router):
...
<PageLayout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/example' component={Example} />
<Switch>
</PageLayout>
...
where PageLayout
is a simple hoc, containing div wrapper with page-layout
class and returning it's children.
Now, let's focus on the component rendering based on route. Usually you would use as component
prop a React Compoment
. But in our case we need to get it dynamically, to apply feature which helps us to avoid FOUC. So our code will look like this:
import asyncRoute from './asyncRoute'
const Home = asyncRoute(() => import('./Home'))
const Example = asyncRoute(() => import('./Example'))
...
<PageLayout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/example' component={Example} />
<Switch>
</PageLayout>
...
to clarify let's also show how asyncRoute.js
module looks like:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Loader from 'components/Loader'
class AsyncImport extends Component {
static propTypes = {
load: PropTypes.func.isRequired,
children: PropTypes.node.isRequired
}
state = {
component: null
}
toggleFoucClass () {
const root = document.getElementById('react-app')
if (root.hasClass('fouc')) {
root.removeClass('fouc')
} else {
root.addClass('fouc')
}
}
componentWillMount () {
this.toggleFoucClass()
}
componentDidMount () {
this.props.load()
.then((component) => {
setTimeout(() => this.toggleFoucClass(), 0)
this.setState(() => ({
component: component.default
}))
})
}
render () {
return this.props.children(this.state.component)
}
}
const asyncRoute = (importFunc) =>
(props) => (
<AsyncImport load={importFunc}>
{(Component) => {
return Component === null
? <Loader loading />
: <Component {...props} />
}}
</AsyncImport>
)
export default asyncRoute
hasClass
,addClass
,removeClass
are polyfills which operates on DOM class attribute.
Loader
is a custom component which shows spinner.
Why setTimeout
?
Just because we need to remove fouc
class in the second tick. Otherwise it would happen in the same as rendering the Component. So it won't work.
As you can see in the AsyncImport
component we modify react root container by adding fouc
class. So HTML for clarity:
<html lang="en">
<head></head>
<body>
<div id="react-app"></div>
</body>
</html>
and another piece of puzzle:
#react-app.fouc
.page-layout *
visibility: hidden
sass to apply when importing of specific component (ie.: Home
, Example
) takes place.
Why not display: none
?
Because we want to have all components which rely on parent width, height or any other css rule to be properly rendered.
How it works?
The main assumption was to hide all elements until compoment gets ready to show us rendered content. First it fires asyncRoute
function which shows us Loader
until Component
mounts and renders. In the meantime in AsyncImport
we switch visibility of content by using a class fouc
on react root DOM element. When everything loads, it's time to show everything up, so we remove that class.
Hope that helps!
Thanks to
This article, which idea of dynamic import has been taken (I think) from react-loadable.
Source
https://turkus.github.io/2018/06/06/fouc-react/
Related Topics
Lining Up Labels with Radio Buttons in Bootstrap
How to Draw a Vertical, Dotted Line Down Center of Page Using CSS
Css: Display: Grid And/Or -Ms-Grid
Is Is Possible to Scale Inline Svg with CSS
How to Specify a CSS Shorthand for "All Elements Except the First/Last"
CSS White Space at Bottom of Page Despite Having Both Min-Height and Height Tag
CSS (Transition) After a Pseudo Element - How to Transition Content That Shows on Hover
How to Centre Absolutely Positioned Content of Unknown Width
How to Place an Image Over Another
Bootstrap 3 Navbar Active Li Not Changing Background-Color
Twitter Bootstrap Responsive Carousel with Multiple Items
Select Last Child When Odd, 2 Last Childs When Even
CSS Relative + Right (Or Bottom) Almost Never Work
Firefox 3 Adds Spacing to Spans with Display:Inline-Block