css-inline is a high-performance library for inlining CSS into HTML 'style' attributes.
This library is designed for scenarios such as preparing HTML emails or embedding HTML into third-party web pages.
For instance, the library transforms HTML like this:
<html>
<head>
<style>h1 { color:blue; }</style>
</head>
<body>
<h1>Big Text</h1>
</body>
</html>into:
<html>
<head></head>
<body>
<h1 style="color:blue;">Big Text</h1>
</body>
</html>- Uses reliable components from Mozilla's Servo project
- Inlines CSS from
styleandlinktags - Removes
styleandlinktags - Resolves external stylesheets (including local files)
- Optionally caches external stylesheets
- Works on Linux, Windows, and macOS
- Supports HTML5 & CSS3
If you'd like to try css-inline, you can check the WebAssembly-powered playground to see the results instantly.
The C bindings are distributed as a header (css_inline.h) along with a dynamic library (libcss_inline.so).
To download them, go to Releases and get the latest archive with the [C] tag.
#include "css_inline.h"
#include <stdio.h>
#define OUTPUT_SIZE 1024
int main(void) {
CssInlinerOptions options = css_inliner_default_options();
const char input[] =
"<html>"
"<head>"
"<style>h1 {color : red}</style>"
"</head>"
"<body>"
"<h1>Test</h1>"
"</body>"
"</ html>";
char output[OUTPUT_SIZE];
if (css_inline_to(&options, input, output, sizeof(output)) == CSS_RESULT_OK) {
printf("Inlined CSS: %s\n", output);
}
// Alternatively, because CSS_RESULT_OK is equal to 0, you can do
CssResult res = css_inline_to(&options, input, output, sizeof(output));
if (!res) {
printf("An error occurred while inlining the CSS, see the result enum type: %d", res);
}
return 0;
}The inline function, css_inline_to(), doesn't allocate, so you must provide an array big enough to fit the result. If the size is not sufficient, the enum CSS_RESULT_IO_ERROR will be returned.
Note that css-inline automatically adds missing html and body tags, so the output is a valid HTML document.
Alternatively, you can inline CSS into an HTML fragment. Structural tags (<html>, <head>, <body>) are stripped from the output; only their contents are preserved. Use css_inline_to if you need to keep the full document structure:
#include "css_inline.h"
#include <stdio.h>
#define OUTPUT_SIZE 1024
int main(void) {
CssInlinerOptions options = css_inliner_default_options();
const char fragment[] =
"<main>"
"<h1>Hello</h1>"
"<section>"
"<p>who am i</p>"
"</section>"
"</main>";
const char css[] =
"p {"
"color: red;"
"}"
"h1 {"
"color: blue;"
"}";
char output[OUTPUT_SIZE];
if (css_inline_fragment_to(&options, fragment, css, output, sizeof(output)) == CSS_RESULT_OK) {
printf("Inlined CSS: %s\n", output);
// HTML becomes this:
// <main>
// <h1 style="color: blue;">Hello</h1>
// <section>
// <p style="color: red;">who am i</p>
// </section>
// </main>
}
return 0;
}You can change the inline behavior by modifying the CssInlinerOptions struct parameter that will be passed to css_inline_to():
#include "css_inline.h"
#include <stdbool.h>
int main(void) {
CssInlinerOptions options = css_inliner_default_options();
options.load_remote_stylesheets = true;
char input[] = "...";
char output[256];
if (!css_inline_to(&options, input, output, sizeof(output))) {
// Deal with the error
}
return 0;
}Possible configurations:
inline_style_tags. Specifies whether to inline CSS from "style" tags. Default:truekeep_style_tags. Specifies whether to keep "style" tags after inlining. Default:falsekeep_link_tags. Specifies whether to keep "link" tags after inlining. Default:falsekeep_at_rules. Specifies whether to keep "at-rules" (starting with@) after inlining. Default:falseminify_css. Specifies whether to remove trailing semicolons and spaces between properties and values.base_url. The base URL used to resolve relative URLs. If you'd like to load stylesheets from your filesystem, use thefile://scheme. Default:NULLload_remote_stylesheets. Specifies whether remote stylesheets should be loaded. Default:truecache. Specifies caching options for external stylesheets. Default:NULLextra_css. Extra CSS to be inlined. Default:NULLpreallocate_node_capacity. Advanced. Preallocates capacity for HTML nodes during parsing. This can improve performance when you have an estimate of the number of nodes in your HTML document. Default:32remove_inlined_selectors. Specifies whether to remove selectors that were successfully inlined from<style>blocks. Default:falseapply_width_attributes. Specifies whether to addwidthHTML attributes from CSSwidthproperties on supported elements (table,td,th,img). Default:falseapply_height_attributes. Specifies whether to addheightHTML attributes from CSSheightproperties on supported elements (table,td,th,img). Default:false
You can also skip CSS inlining for an HTML tag by adding the data-css-inline="ignore" attribute to it:
<html>
<head>
<style>h1 { color:blue; }</style>
</head>
<body>
<!-- The tag below won't receive additional styles -->
<h1 data-css-inline="ignore">Big Text</h1>
</body>
</html>The data-css-inline="ignore" attribute also allows you to skip link and style tags:
<head>
<!-- Styles below are ignored -->
<style data-css-inline="ignore">h1 { color:blue; }</style>
</head>
<body>
<h1>Big Text</h1>
</body>Alternatively, you may keep style from being removed by using the data-css-inline="keep" attribute.
This is useful if you want to keep @media queries for responsive emails in separate style tags.
Such tags will be kept in the resulting HTML even if the keep_style_tags option is set to false.
<head>
<!-- Styles below are not removed -->
<style data-css-inline="keep">h1 { color:blue; }</style>
</head>
<body>
<h1>Big Text</h1>
</body>Another possibility is to set keep_at_rules option to true. At-rules cannot be inlined into HTML therefore they
get removed by default. This is useful if you want to keep at-rules, e.g. @media queries for responsive emails in
separate style tags but inline any styles which can be inlined.
Such tags will be kept in the resulting HTML even if the keep_style_tags option is explicitly set to false.
<head>
<!-- With keep_at_rules=true "color:blue" will get inlined into <h1> but @media will be kept in <style> -->
<style>h1 { color: blue; } @media (max-width: 600px) { h1 { font-size: 18px; } }</style>
</head>
<body>
<h1>Big Text</h1>
</body>If you set the the minify_css option to true, the inlined styles will be minified by removing trailing semicolons
and spaces between properties and values.
<head>
<!-- With minify_css=true, the <h1> will have `style="color:blue;font-weight:bold"` -->
<style>h1 { color: blue; font-weight: bold; }</style>
</head>
<body>
<h1>Big Text</h1>
</body>You can also cache external stylesheets to avoid excessive network requests:
int main(void) {
// Configure cache
StylesheetCache cache = css_inliner_stylesheet_cache(8);
CssInlinerOptions options = css_inliner_default_options();
options.cache = &cache;
// ... Inline CSS
return 0;
}Caching is disabled by default.
This project is licensed under the terms of the MIT license.