什么是Critical Css
首屏關(guān)鍵css
網(wǎng)頁渲染時漠魏,瀏覽器解析只有在完成<head>
部分 CSS 樣式的加載倔矾、解析之后才會渲染頁面。這種渲染方式意味著,如果 CSS 文件很大哪自,那么用戶就必須等待很長的時間才能看到渲染結(jié)果丰包。針對這一問題,提出一種非常規(guī)的解決方案壤巷,提高頁面的渲染速度邑彪,這一方案常被稱為critical rendering path
(關(guān)鍵渲染路徑)。我們要做的優(yōu)化就是找出渲染首屏的最小 CSS 集合(Critical CSS)胧华,并把它們寫到<head>
部分寄症,從而讓瀏覽器接收到 HTML 文件后就盡快渲染出頁面。對于剩余部分的 CSS矩动,我們可以使用異步的方式進行加載有巧。
總結(jié):Critical Css就是渲染首屏的最小CSS集合。
通過criticalcss網(wǎng)站獲取頁面critical css【收費】
Vue-cli客戶端提取Critical css
提取css
以vue-cli4
為例
css.extract
- Type: boolean | Object
- Default: 生產(chǎn)環(huán)境下是 true悲没,開發(fā)環(huán)境下是 false
是否將組件中的 CSS 提取至一個獨立的 CSS 文件中 (而不是動態(tài)注入到 JavaScript 中的 inline 代碼)篮迎。
同樣當(dāng)構(gòu)建 Web Components 組件時它總是會被禁用 (樣式是 inline 的并注入到了 shadowRoot 中)。
當(dāng)作為一個庫構(gòu)建時示姿,你也可以將其設(shè)置為 false 免得用戶自己導(dǎo)入 CSS甜橱。
提取 CSS 在開發(fā)環(huán)境模式下是默認(rèn)不開啟的,因為它和 CSS 熱重載不兼容峻凫。然而渗鬼,你仍然可以將這個值顯性地設(shè)置為 true 在所有情況下都強制提取。
-
開發(fā)環(huán)境
extract
為false
荧琼,樣式內(nèi)嵌到head
中譬胎。
開發(fā)環(huán)境.png -
生產(chǎn)環(huán)境
extract
為true
,樣式分離命锄,外鏈到head
中堰乔。
形成兩個css文件:
app.[contetHash].css:vue組件抽離出來的css
chunk-vendors.[contentHash].css:第三方庫依賴的css
內(nèi)部插件
- mini-css-extract-plugin:CSS 提取到單獨的文件中,為每個包含 CSS 的 JS 文件創(chuàng)建一個 CSS 文件脐恩,并且支持 CSS 和 SourceMaps 的按需加載
- @intervolga/optimize-cssnano-plugin:優(yōu)化和壓縮css
不足
要么樣式全部內(nèi)嵌在head
中導(dǎo)致html
文件過大镐侯,要么外鏈,如果出現(xiàn)網(wǎng)絡(luò)問題驶冒,頁面白屏?xí)r間過長苟翻。
針對這一不足,我們看一下在vue
客戶端項目中如何提取首屏渲染csscritical css
骗污。
提取critical css
使用webpack
插件critical-css-webpack-plugin
critical-css-webpack-plugin
項目配置
以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`傳遞配置對象
inline: true,
// type: string蜡歹,讀取和寫入源的目錄
base: resolve('dist'),
// type: string,要操作的html源代碼涕烧,此選項優(yōu)先于src選項
// html: '',
// type: array月而,css路徑的數(shù)組
// css: [],
// type: string,要操作的html源代碼的位置
src: 'index.html',
// type: string议纯,保存操作輸出的位置父款,如果要同時存儲`html`和`css`,使用`html`和`css`的對象
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選項
dimensions: [],
// type: boolean包晰,是否壓縮生成的critical-path css
minify: true,
// type: boolean,小心使用炕吸,從html中刪除inline樣式伐憾,它會基于提取的內(nèi)容生成新的引用,因此可以安全地在多個html文件引用同一樣式文件赫模。刪除每頁的關(guān)鍵css會為每個頁面生成唯一一個異步加載css树肃。意味著你不能跨多頁面緩存
extract: false,
// type: boolean,inline圖片
inlineImages: true,
// type: array瀑罗,內(nèi)聯(lián)程序開始查詢assets時的目錄/url列表
assetPaths: [],
// 設(shè)置base64內(nèi)聯(lián)圖片的最大大行刈臁(以字節(jié)為單位)
maxImageFileSize: 10240000,
// type: object/function,critical嘗試相對文檔的assets path
rebase: undefined,
// type: array
ignore: [],
// type: string斩祭,獲取遠(yuǎn)程src時的用戶代理
// userAgent: '',
// type: object,penthouse的配置選項
penthouse: {
// propertiesToRemove: ['background'],
// 強制包含的selector
forceInclude: ['.card', '.card__list', '.card__main', '.card__img', '.card__article'],
forceExclude: []
},
// type: object劣像,got的配置選項
request: {},
// type: string,RFC2617授權(quán):user
user: undefined,
// type: string摧玫,RFC2617授權(quán):pass
pass: undefined,
// type: boolean耳奕,如果找不到css,則拋出錯誤
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
文件也不會很大,也可以保證在網(wǎng)絡(luò)不穩(wěn)定時癞揉,顯示簡單頁面樣式。
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
對應(yīng)
critical插件
中的penthouse
options
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ù)端渲染時,管理 CSS 的推薦方法是簡單地使用 *.vue
單個文件組件內(nèi)的<style>
壁拉,它提供:
- 與 HTML 并列同級谬俄,組件作用域 CSS
- 能夠使用預(yù)處理器(pre-processor)或 PostCSS
- 開發(fā)過程中熱重載(hot-reload)
更重要的是,vue-style-loader
(vue-loader
內(nèi)部使用的 loader)弃理,具備一些服務(wù)器端渲染的特殊功能:
客戶端和服務(wù)器端的通用編程體驗溃论。
在使用
bundleRenderer
時,自動注入關(guān)鍵 CSS(critical CSS)痘昌。如果在服務(wù)器端渲染期間使用钥勋,可以在 HTML 中收集和內(nèi)聯(lián)(使用 template 選項時自動處理)組件的 CSS。在客戶端辆苔,當(dāng)?shù)谝淮问褂迷摻M件時算灸,vue-style-loader 會檢查這個組件是否已經(jīng)具有服務(wù)器內(nèi)聯(lián)(server-inlined)的 CSS - 如果沒有,CSS 將通過
<style>
標(biāo)簽動態(tài)注入驻啤。
demo示例
pages/index.vue
為首屏渲染頁面
<template>
<div class="index">首頁</div>
</template>
<style>
.index {
color: red;
}
</style>
新建pages/test.vue
頁面菲驴,驗證SSR是否會自動注入關(guān)鍵css(critical css
)
<template>
<div class="test">測試</div>
</template>
<style>
.test {
color: red;
}
</style>
- 在
index.vue
中引入test.vue
,服務(wù)啟動后骑冗,test.vue
樣式也以style
形式內(nèi)嵌在頁面中 - 不在
index.vue
中引入test.vue
赊瞬,服務(wù)啟動后,test.vue
樣式則沒有內(nèi)嵌在首屏渲染頁面中
總結(jié):SSR服務(wù)端會自動注入首屏渲染關(guān)鍵css沐旨,無需引入其他插件森逮。
提取CSS
以nuxt
框架配置為例nuxt.config.js
SSR可通過extractCSS
將css提取到獨立的文件中,方便緩存磁携。
export default {
build: {
extractCSS: true,
}
}
總結(jié)
- 客戶端和服務(wù)端均可通過
extract
提取css
至單獨文件中褒侧,以外鏈形式引入 - 客戶端只可內(nèi)嵌
css
至head
中,或提取成單獨文件外鏈引入谊迄,不可提取critical css
闷供,需要增加額外webpack plugin來提取 - 服務(wù)端自動注入
critical css
,不需額外引入其他插件