Home > Article > Web Front-end > Detailed explanation of automated methods to reduce render-blocking CSS
"Eliminate render-blocking JavaScript and CSS". This is the Google Page Speed Insights recommendation that I always stick to. Google recommends that you inline the CSS you initially need (inline) and load the rest of the CSS when the page is ready to load , and use the idle time to load other content. This way, users can see the page as early as possible.
We can do a lot of things to minimize JavaScript’s delegate blocking, such as code splitting, tree shaking, caching, etc.
What about CSS? To do this, we can minimize delegate blocking by isolating the CSS used for the above content (i.e. the critical CSS) and loading it first. Then we can load non-critical CSS.
Isolating critical CSS is possible programmatically, and in this article I'll show you how to delegate it to the Webpack pipeline.
What does rendering blocking mean? If a resource is "render-blocking" it means that the browser cannot display the page until the resource is downloaded or processed.
Normally, we load the CSS in a blocking way by linking to the stylesheet at the head of the document, like this:
<head> <link rel="stylesheet" href="/style.css"> ... </head> <body> <p>I can't be seen until style.css has been loaded!</p> </body>
When the web browser loads this page , it will read it from beginning to end. When the browser reaches the link tag, it will immediately start downloading the style sheet and will not render the page until it completes.
For large sites, especially sites with large frameworks like Bootstrap, the stylesheet may be hundreds of kb, and users must wait patiently until it is completely downloaded.
So, should we link to the stylesheet in the body, where rendering won't block? You can do that, but the thing is, blocking tenants isn't entirely a bad thing, we actually want to take advantage of it. If the page renders without any CSS loaded, we get ugly "flash unstyled content":
The sweet spot we want is where to render, with the key The css blocks the page, which is required to style the main view, but all non-critical css is loaded after the initial render.
Key CSS Take a look at this simple page I built with Bootstrap and Webpack. This is what it looks like after it's first rendered:
The page also has a modal that can be opened via the "Register Now" button. Once opened, it looks like this:
For the first rendering of the page, we need nav bar, jumbotron, button and some other general rules of layout and fonts css rules. But we don't need the modal rules because it won't be shown immediately. With this in mind, we can separate critical css from non-critical css:
critical.css
.nav { ... } .jumbtron { ... } .btn { ... }
non_critical.css
.modal { ... }
If you agree with this concept, you probably You will be interested in the following two questions:
Sample Project I'm going to briefly walk you through the basic setup of this project so you can digest it quickly when we find a solution.
First, I load bootstrap SASS into my input file.
main.js
require("bootstrap-sass/assets/stylesheets/_bootstrap.scss");
I'm handling this using sass-loader and combining it with the Extract Text Plugin to put the compiled CSS into its own file.
I also use the HTML Webpack plugin to create the HTML files in the build. As you will soon see, this solution is essential.
webpack.config.js
module.exports = { module: { rules: [ { test: /\.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, ... ] }, ... plugins: [ new ExtractTextPlugin({ filename: 'style.css' }), new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', inject: true }) ] };
After running the build, the HTML file looks like this. Note that the CSS is loaded in the head and therefore blocks rendering.
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>vuestrap-code-split</title> <link href="/style.css" rel="stylesheet"> </head> <body> <!--App content goes here, omitted for brevity.--> <script type="text/javascript" src="/build_main.js"></script> </body> </html>
Identifying critical CSS programmaticallyIdentifying critical CSS manually can be cumbersome. To do this programmatically, we can use a tool aptly named
Criticalby Addy Osmani. This is a Node.js module that will read an HTML document and identify critical CSS. There's more to it than that, as we'll see shortly. Critical's method of identifying critical CSS is to load the page using PhantomJS, using the specified screen dimensions, and extract any CSS rules used in rendering the page.
Here's how we set it up for this project:
const critical = require("critical"); critical.generate({ /* The path of the Webpack bundle */ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, extract: true, /* iPhone 6 dimensions, use whatever you like*/ width: 375, height: 565, /* Ensure that bundled JS file is called */ penthouse: { blockJSRequests: false, } });
执行时,这将把Webpack包输出中的HTML文件更新为:
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Bootstrap Critical</title> <style type="text/css"> /* Critical CSS is inlined into the document head, abbreviated here. */ body { font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 14px; line-height: 1.42857; color: #333; background-color: #fff; } ... </style> <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'"> <noscript> <link href="/style.96106fab.css" rel="stylesheet"> </noscript> <script> /*A script for loading the non-critical CSS goes here, omitted for brevity.*/ </script> </head> <body> <!--App content goes here, omitted for brevity.--> <script type="text/javascript" src="/build_main.js"></script> </body> </html>
它还将输出一个新的css文件,例如style.96106fab.css(文件名会自动添加一个散列)。这个css文件与原始样式表相同,只是去掉了关键的css。
内联关键css
您将注意到关键的CSS已内联到文档的头部。这是最优的,因为页面不必从服务器加载它。
预加载非关键CSS
您还将注意到,非关键CSS加载了外观精美的链接。 preload值告诉浏览器开始获取非关键CSS供挂起使用。 但至关重要的是,预加载不是渲染阻止,因此无论预加载资源是否完成,浏览器都将继续绘制页面。
链接中的onload属性允许我们在非关键的CSS最终加载后运行脚本。关键模块自动将脚本内联到文档中,从而提供跨浏览器兼容的方式将非关键样式表加载到页面中。
<link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
将critical放入webpack管道
我制作了一个名为html关键webpack plugin的webpack插件,它仅仅是关键模块的包装器。它将在您的文件从HTML网页包插件发出后运行。
以下是如何将它包含在Webpack项目中:
const HtmlCriticalPlugin = require("html-critical-webpack-plugin"); module.export = { ... plugins: [ new HtmlWebpackPlugin({ ... }), new ExtractTextPlugin({ ... }), new HtmlCriticalPlugin({ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, minify: true, extract: true, width: 375, height: 565, penthouse: { blockJSRequests: false, } }) ] };
注意:您可能只应该在生产构建中使用它,而不是在开发中,因为它会使您的构建非常慢!
性能结果
现在我已经隔离了关键的CSS,并在空闲时间加载了非关键的CSS,那么如何改进性能呢?
我使用Chrome的灯塔扩展来寻找答案。请记住,我们试图优化的度量标准是第一次有意义的绘制的时间,它基本上告诉我们用户看到某些东西需要多长时间。
在实施关键的CSS:
关键的CSS实现后:
如您所见,我的应用程序在整整一秒钟前就获得了一幅有意义的画作,并且在半秒钟前就实现了交互。
实际上,你可能不会在你的应用程序中得到如此显著的改进,因为我的css已经完全膨胀了(我包括了整个引导库),在这样一个简单的应用程序中,我没有很多关键的css规则。
英文原文地址:https://vuejsdevelopers.com/2017/07/24/critical-css-webpack/
更多编程相关知识,请访问:编程课程!!
The above is the detailed content of Detailed explanation of automated methods to reduce render-blocking CSS. For more information, please follow other related articles on the PHP Chinese website!