posthtml-css-inline v0.2.1
This is a work in progress, it's not ready for production yet.
TODO:
- Support
<link rel="stylesheet">tags - Remove inlined selectors from HTML elements
- Support PostCSS plugins
- Support complex selectors *
- Safelist (selectors that should not be inlined)
- Skip inlining on marked tags
- Juice-compatible options
excludedPropertiesresolveCSSVariablesapplyHeightAttributesapplyWidthAttributesapplyAttributesTableElements
* This needs to be implemented in PostHTML or posthtml-match-helper first.
About
This plugin will inline CSS from <style> and <link rel="stylesheet"> tags into HTML style attributes.
The CSS will be parsed with PostCSS, so you can use PostCSS plugins to transform the CSS before it's inlined.
Use cases:
- HTML emails
- Embedding HTML in 3rd party websites
Given something like this:
<style>
div {
color: red;
}
@media (max-width: 600px) {
.text-sm {
font-size: 16px;
}
}
</style>
<div class="text-sm">Test</div>... it will output:
<style>
div {
color: red;
}
@media (max-width: 600px) {
.text-sm {
font-size: 16px;
}
}
</style>
<div class="text-sm" style="color: red;">Test</div>Install
$ npm i posthtml posthtml-css-inlineUsage
To use the plugin, simply pass it to PostHTML:
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss(options)
])
.process('your HTML')
.then(result => console.log(result.html))Options
You may configure how inlining works by passing an options object to the plugin.
| Option | Type | Default | Description |
|---|---|---|---|
processLinkTags | boolean | false | Process <link rel="stylesheet"> tags. |
preserveImportant | boolean | false | Preserve !important in the inlined CSS value. |
removeInlinedSelectors | boolean | false | Remove selectors that were successfully inlined from both the <style> tag and from the HTML body. |
postcss | object | {} | Object to configure PostCSS. |
safelist | array | [] | Array of selectors that should not be inlined. |
excludedProperties | array | [] | Array of CSS properties that should not be inlined. |
Attributes
You may configure how inlining works on a per-element basis.
| Attribute | Description |
|---|---|
no-inline | Skip inlining on this element. |
processLinkTags
Type: boolean\
Default: false
Whether to process <link rel="stylesheet"> tags.
The plugin will fetch the CSS from the URL in the href attribute, and replace the <link> tag with a <style> tag containing the CSS. This <style> tag will then be inlined into the HTML.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss({
processLinkTags: true
})
])
.process(`
<link rel="stylesheet" href="public/styles.css">
<p class="text-sm">small text</p>
`)
.then(result => result.html)/* public/styles.css */
.text-sm {
font-size: 12px;
}Result:
<p class="text-sm" style="font-size: 12px">small text</p>preserveImportant
Type: boolean\
Default: false
Whether to preserve !important in the inlined CSS value.
For example this:
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss({
preserveImportant: true
})
])
.process(`
<style>
.text-sm {
font-size: 12px;
}
div {
font-size: 14px !important;
}
</style>
<p class="text-sm">small text</p>
`)
.then(result => result.html)... will output this:
<p class="text-sm" style="font-size: 14px !important">small text</p>removeInlinedSelectors
Type: boolean\
Default: false
Whether to remove selectors that were successfully inlined from both the <style> tag and from the HTML body.
If a selector that has been inlined is also present inside an at-rule such as @media, it will not be removed from the HTML body.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss({
removeInlinedSelectors: true
})
])
.process(`
<style>
.text-sm {
font-size: 12px;
}
@media (min-width: 640px) {
.text-sm {
font-size: 16px !important;
}
}
</style>
<p class="text-sm">small text</p>
`)
.then(result => result.html)Result:
<style>
@media (min-width: 640px) {
.text-sm {
font-size: 16px !important;
}
}
</style>
<p class="text-sm" style="font-size: 12px">small text</p>postcss
Type: object\
Default: {}
You may configure PostCSS and use PostCSS plugins to transform the CSS before it's inlined.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
// Imaginary PostCSS plugin that removes !important
import removeImportant from'remove-important-plugin'
posthtml([
inlineCss({
postcss: {
plugins: [
removeImportant
]
}
})
])
.process(`
<style>
.text-sm {
font-size: 12px !important;
}
@media (min-width: 640px) {
.text-sm {
font-size: 16px !important;
}
}
</style>
<p class="text-sm">small text</p>
`)
.then(result => result.html)Result:
<style>
.text-sm {
font-size: 12px;
}
@media (min-width: 640px) {
.text-sm {
font-size: 16px;
}
}
</style>
<p class="text-sm" style="font-size: 12px">small text</p>safelist
Type: array\
Default: []
Array of selectors that should not be inlined.
!NOTE
The CSS*selector is not supported when inlining, you don't need to worry about safelisting it.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss({
safelist: ['body', '.flex']
})
])
.process(`
<style>
.flex {
display: flex;
}
body {
color: blue;
}
p {
color: red;
}
</style>
<body>
<p class="flex">small text</p>
</body>
`)
.then(result => result.html)Result:
<body>
<p class="flex" style="color: red">small text</p>
</body>excludedProperties
Type: array\
Default: []
Array of CSS properties that should not be inlined.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss({
excludedProperties: ['color', 'display']
})
])
.process(`
<style>
p {
color: red;
display: flex;
font-size: 12px;
}
</style>
<p>text</p>
`)
.then(result => result.html)Result:
<style>
p {
color: red;
display: flex;
font-size: 12px;
}
</style>
<p style="font-size: 12px">text</p>no-inline
You may use the no-inline attribute on an element to prevent CSS inlining.
- when used on a
<style>or<link>tag, the CSS inside the tag will not be inlined - when used on any other tag, the inliner will not inline CSS on that tag
You may use any of the following attributes to achieve this on a <style> or <link> tag:
no-inlinedata-embedembedprevent-inlineskip-inline
Likewise, you may use any of the following attributes to achieve this on any other tag:
no-inlineprevent-inlineskip-inline
The attribute will be removed from the tag in the resulting HTML.
import posthtml from'posthtml'
import inlineCss from'posthtml-css-inline'
posthtml([
inlineCss()
])
.process(`
<style no-inline>
p {
font-size: 12px;
}
</style>
<style>
div {
color: blue;
}
</style>
<p>small text</p>
<div no-inline>b</div>
`)
.then(result => result.html)Result:
<style>
p {
font-size: 12px;
}
</style>
<style>
div {
color: blue;
}
</style>
<p>small text</p>
<div>b</div>