什么是Critical Css
首屏關(guān)鍵css
網(wǎng)頁渲染時(shí),瀏覽器解析只有在完成<head>部分 CSS 樣式的加載、解析之后才會(huì)渲染頁面。這種渲染方式意味著,如果 CSS 文件很大,那么用戶就必須等待很長的時(shí)間才能看到渲染結(jié)果。針對(duì)這一問題,提出一種非常規(guī)的解決方案,提高頁面的渲染速度,這一方案常被稱為critical rendering path(關(guān)鍵渲染路徑)。我們要做的優(yōu)化就是找出渲染首屏的最小 CSS 集合(Critical CSS),并把它們寫到<head>部分,從而讓瀏覽器接收到 HTML 文件后就盡快渲染出頁面。對(duì)于剩余部分的 CSS,我們可以使用異步的方式進(jìn)行加載。
總結(jié):Critical Css就是渲染首屏的最小CSS集合。
通過criticalcss網(wǎng)站獲取頁面critical css【收費(fèi)】
Vue-cli客戶端提取Critical css
提取css
以vue-cli4為例
css.extract
- Type: boolean | Object
- Default: 生產(chǎn)環(huán)境下是 true,開發(fā)環(huán)境下是 false
是否將組件中的 CSS 提取至一個(gè)獨(dú)立的 CSS 文件中 (而不是動(dòng)態(tài)注入到 JavaScript 中的 inline 代碼)。
同樣當(dāng)構(gòu)建 Web Components 組件時(shí)它總是會(huì)被禁用 (樣式是 inline 的并注入到了 shadowRoot 中)。
當(dāng)作為一個(gè)庫構(gòu)建時(shí),你也可以將其設(shè)置為 false 免得用戶自己導(dǎo)入 CSS。
提取 CSS 在開發(fā)環(huán)境模式下是默認(rèn)不開啟的,因?yàn)樗?CSS 熱重載不兼容。然而,你仍然可以將這個(gè)值顯性地設(shè)置為 true 在所有情況下都強(qiáng)制提取。
-
開發(fā)環(huán)境
extract為false,樣式內(nèi)嵌到head中。
開發(fā)環(huán)境.png -
生產(chǎn)環(huán)境
extract為true,樣式分離,外鏈到head中。
形成兩個(gè)css文件:
app.[contetHash].css:vue組件抽離出來的css
chunk-vendors.[contentHash].css:第三方庫依賴的css
內(nèi)部插件
- mini-css-extract-plugin:CSS 提取到單獨(dú)的文件中,為每個(gè)包含 CSS 的 JS 文件創(chuàng)建一個(gè) CSS 文件,并且支持 CSS 和 SourceMaps 的按需加載
- @intervolga/optimize-cssnano-plugin:優(yōu)化和壓縮css
不足
要么樣式全部內(nèi)嵌在head中導(dǎo)致html文件過大,要么外鏈,如果出現(xiàn)網(wǎng)絡(luò)問題,頁面白屏?xí)r間過長。
針對(duì)這一不足,我們看一下在vue客戶端項(xiàng)目中如何提取首屏渲染csscritical css。
提取critical css
使用webpack插件critical-css-webpack-plugin
critical-css-webpack-plugin
項(xiàng)目配置
以vue-cli4.x為例
Install
npm install critical-css-webpack-plugin -D
vue.config.js
const criticalCssWebpackPlugin = require('critical-css-webpack-plugin')
/ critical css Options
const criticalCssOptions = {
// type: boolean/object,是否inline生成的critical-path css。
// true:生成html,false:生成css,object:向`inline-critical`傳遞配置對(duì)象
inline: true,
// type: string,讀取和寫入源的目錄
base: resolve('dist'),
// type: string,要操作的html源代碼,此選項(xiàng)優(yōu)先于src選項(xiàng)
// html: '',
// type: array,css路徑的數(shù)組
// css: [],
// type: string,要操作的html源代碼的位置
src: 'index.html',
// type: string,保存操作輸出的位置,如果要同時(shí)存儲(chǔ)`html`和`css`,使用`html`和`css`的對(duì)象
target: 'index.html',
// type: integer,1300,目標(biāo)視口的寬度
width: 1300,
// type: integer,900,目標(biāo)視口的高度
height: 900,
// type: array,包含寬度和高度的數(shù)組,如果設(shè)置,優(yōu)先于width和height選項(xiàng)
dimensions: [],
// type: boolean,是否壓縮生成的critical-path css
minify: true,
// type: boolean,小心使用,從html中刪除inline樣式,它會(huì)基于提取的內(nèi)容生成新的引用,因此可以安全地在多個(gè)html文件引用同一樣式文件。刪除每頁的關(guān)鍵css會(huì)為每個(gè)頁面生成唯一一個(gè)異步加載css。意味著你不能跨多頁面緩存
extract: false,
// type: boolean,inline圖片
inlineImages: true,
// type: array,內(nèi)聯(lián)程序開始查詢assets時(shí)的目錄/url列表
assetPaths: [],
// 設(shè)置base64內(nèi)聯(lián)圖片的最大大?。ㄒ宰止?jié)為單位)
maxImageFileSize: 10240000,
// type: object/function,critical嘗試相對(duì)文檔的assets path
rebase: undefined,
// type: array
ignore: [],
// type: string,獲取遠(yuǎn)程src時(shí)的用戶代理
// userAgent: '',
// type: object,penthouse的配置選項(xiàng)
penthouse: {
// propertiesToRemove: ['background'],
// 強(qiáng)制包含的selector
forceInclude: ['.card', '.card__list', '.card__main', '.card__img', '.card__article'],
forceExclude: []
},
// type: object,got的配置選項(xiàng)
request: {},
// type: string,RFC2617授權(quán):user
user: undefined,
// type: string,RFC2617授權(quán):pass
pass: undefined,
// type: boolean,如果找不到css,則拋出錯(cuò)誤
strict: false
};
module.exports = {
chainWebpack: config => {
config.plugin('critical')
.use(criticalCssWebpackPlugin,
[
criticalCssOptions
]
).tap(error => {
console.log(error, 'critical css generate error');
return error
})
}
}
配置完畢后,執(zhí)行npm run build構(gòu)建,查看dist/index.html,可以看到提取的critical css插入到head中,剩余css仍以外鏈形式引入。
這樣index.html文件也不會(huì)很大,也可以保證在網(wǎng)絡(luò)不穩(wěn)定時(shí),顯示簡單頁面樣式。
critical-css-webpack-plugin插件的核心是critical,critical核心使用penthouse,接下來再詳解一下critical和penthouse。
critical插件
critical插件介紹,使用到核心組件庫penthouse。
從
html中提取critical css,并將critical-path內(nèi)聯(lián)到html中
Install
npm i -D critical
Usage
配置文件critical.js:
const critical = require('critical');
critical.generate({
// Inline the generated critical-path CSS
// - true generates HTML
// - false generates CSS
inline: true,
...
});
node環(huán)境下執(zhí)行配置文件critical.js即可
node critical.js
Critical Options
摘自https://www.npmjs.com/package/critical
| Name | Type | Default | Description |
|---|---|---|---|
| inline | boolean/object | false | Inline critical-path CSS using filamentgroup's loadCSS. Pass an object to configure inline-critical |
| base | string | path.dirname(src) or process.cwd() | Base directory in which the source and destination are to be written |
| html | string | HTML source to be operated against. This option takes precedence over the src option. | |
| css | array | [] | An array of paths to css files, file globs or Vinyl file objects. |
| src | string | Location of the HTML source to be operated against | |
| target | string or object | Location of where to save the output of an operation. Use an object with 'html' and 'css' props if you want to store both | |
| width | integer | 1300 | Width of the target viewport |
| height | integer | 900 | Height of the target viewport |
| dimensions | array | [] | An array of objects containing height and width. Takes precedence over width and height if set |
| minify | boolean | true | Enable minification of generated critical-path CSS |
| extract | boolean | false | Remove the inlined styles from any stylesheets referenced in the HTML. It generates new references based on extracted content so it's safe to use for multiple HTML files referencing the same stylesheet. Use with caution. Removing the critical CSS per page results in a unique async loaded CSS file for every page. Meaning you can't rely on cache across multiple pages |
| inlineImages | boolean | false | Inline images |
| assetPaths | array | [] | List of directories/urls where the inliner should start looking for assets |
| maxImageFileSize | integer | 10240 | Sets a max file size (in bytes) for base64 inlined images |
| rebase | object or function | undefined | Critical tries it's best to rebase the asset paths relative to the document. If this doesn't work as expected you can always use this option to control the rebase paths. See postcss-url for details. (https://github.com/pocketjoso/penthouse#usage-1). |
| ignore | array | object | undefined |
| userAgent | string | '' | User agent to use when fetching a remote src |
| penthouse | object | {} | Configuration options for penthouse. |
| request | object | {} | Configuration options for got. |
| user | string | undefined | RFC2617 basic authorization: user |
| pass | string | undefined | RFC2617 basic authorization: pass |
| strict | boolean | false | Throw an error if no css is found |
Global Install And Cli
npm install -g critical
critical test/fixture/index.html --base test/fixture > critical.css
penthouse
關(guān)鍵路徑css生成器
Install
npm i -D penthouse
Usage
penthouse({
url: 'http://google.com',
cssString: 'body { color: red }'
...
})
.then(criticalCss => {
// use the critical css
fs.writeFileSync('outfile.css', criticalCss);
})
Options
對(duì)應(yīng)
critical插件中的penthouseoptions
| Name | Type | Default | Description |
|---|---|---|---|
| url | string | Accessible url. Use file:/// protocol for local html files. | |
| cssString | string | Original css to extract critical css from | |
| css | string | Path to original css file on disk (if using instead of cssString) | |
| width | integer | 1300 | Width for critical viewport |
| height | integer | 900 | Height for critical viewport |
| screenshots | object | Configuration for screenshots (not used by default). See Screenshot example | |
| keepLargerMediaQueries | boolean | false | Keep media queries even for width/height values larger than critical viewport. |
| forceInclude | array | [] | Array of css selectors to keep in critical css, even if not appearing in critical viewport. Strings or regex (f.e. ['.keepMeEvenIfNotSeenInDom', /^.button/]) |
| forceExclude | array | [] | Array of css selectors to remove in critical css, even if appearing in critical viewport. Strings or regex (f.e. ['.doNotKeepMeEvenIfNotSeenInDom', /^.button/]) |
| propertiesToRemove | array | ['(.)transition(.)', 'cursor', 'pointer-events', '(-webkit-)?tap-highlight-color', '(.*)user-select'] ] Css properties to filter out from critical css | |
| timeout | integer | 30000 | Ms; abort critical CSS generation after this time |
| puppeteer | object | Settings for puppeteer. See Custom puppeteer browser example | |
| pageLoadSkipTimeout | integer | 0 | Ms; stop waiting for page load after this time (for sites when page load event is unreliable) |
| renderWaitTime | integer | 100 | ms; wait time after page load before critical css extraction starts (also before "before" screenshot is taken, if used) |
| blockJSRequests | boolean | true | set to false to load JS (not recommended) |
| maxEmbeddedBase64Length | integer | 1000 | characters; strip out inline base64 encoded resources larger than this |
| maxElementsToCheckPerSelector | integer | undefined | Can be specified to limit nr of elements to inspect per css selector, reducing execution time. |
| userAgent | string | 'Penthouse Critical Path CSS Generator' | specify which user agent string when loading the page |
| customPageHeaders | object | et extra http headers to be sent with the request for the url. | |
| cookies | array | [] | For formatting of each cookie, see Puppeteer setCookie docs |
| strict | boolean | false | Make Penthouse throw on errors parsing the original CSS. Legacy option, not recommended. |
| allowedResponseCode | number|regex|function | Let Penthouse stop if the server response code is not matching this value. number and regex types are tested against the response.status(). A function is also allowed and gets Response as argument. The function should return a boolean. |
SSR服務(wù)端提取Critical css
簡介
SSR服務(wù)端渲染時(shí),管理 CSS 的推薦方法是簡單地使用 *.vue 單個(gè)文件組件內(nèi)的<style>,它提供:
- 與 HTML 并列同級(jí),組件作用域 CSS
- 能夠使用預(yù)處理器(pre-processor)或 PostCSS
- 開發(fā)過程中熱重載(hot-reload)
更重要的是,vue-style-loader(vue-loader 內(nèi)部使用的 loader),具備一些服務(wù)器端渲染的特殊功能:
客戶端和服務(wù)器端的通用編程體驗(yàn)。
在使用
bundleRenderer時(shí),自動(dòng)注入關(guān)鍵 CSS(critical CSS)。如果在服務(wù)器端渲染期間使用,可以在 HTML 中收集和內(nèi)聯(lián)(使用 template 選項(xiàng)時(shí)自動(dòng)處理)組件的 CSS。在客戶端,當(dāng)?shù)谝淮问褂迷摻M件時(shí),vue-style-loader 會(huì)檢查這個(gè)組件是否已經(jīng)具有服務(wù)器內(nèi)聯(lián)(server-inlined)的 CSS - 如果沒有,CSS 將通過
<style>標(biāo)簽動(dòng)態(tài)注入。
demo示例
pages/index.vue為首屏渲染頁面
<template>
<div class="index">首頁</div>
</template>
<style>
.index {
color: red;
}
</style>
新建pages/test.vue頁面,驗(yàn)證SSR是否會(huì)自動(dòng)注入關(guān)鍵css(critical css)
<template>
<div class="test">測試</div>
</template>
<style>
.test {
color: red;
}
</style>
- 在
index.vue中引入test.vue,服務(wù)啟動(dòng)后,test.vue樣式也以style形式內(nèi)嵌在頁面中 - 不在
index.vue中引入test.vue,服務(wù)啟動(dòng)后,test.vue樣式則沒有內(nèi)嵌在首屏渲染頁面中
總結(jié):SSR服務(wù)端會(huì)自動(dòng)注入首屏渲染關(guān)鍵css,無需引入其他插件。
提取CSS
以nuxt框架配置為例nuxt.config.js
SSR可通過extractCSS將css提取到獨(dú)立的文件中,方便緩存。
export default {
build: {
extractCSS: true,
}
}
總結(jié)
- 客戶端和服務(wù)端均可通過
extract提取css至單獨(dú)文件中,以外鏈形式引入 - 客戶端只可內(nèi)嵌
css至head中,或提取成單獨(dú)文件外鏈引入,不可提取critical css,需要增加額外webpack plugin來提取 - 服務(wù)端自動(dòng)注入
critical css,不需額外引入其他插件