Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stranger6667/css-inline
High-performance library for inlining CSS into HTML 'style' attributes
https://github.com/stranger6667/css-inline
css css-inline hacktoberfest html javascript python ruby rust wasm
Last synced: 3 days ago
JSON representation
High-performance library for inlining CSS into HTML 'style' attributes
- Host: GitHub
- URL: https://github.com/stranger6667/css-inline
- Owner: Stranger6667
- License: mit
- Created: 2020-06-21T12:32:19.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-10-25T23:08:56.000Z (2 months ago)
- Last Synced: 2024-10-29T15:48:31.266Z (2 months ago)
- Topics: css, css-inline, hacktoberfest, html, javascript, python, ruby, rust, wasm
- Language: Rust
- Homepage: https://css-inline.org/
- Size: 3.64 MB
- Stars: 239
- Watchers: 4
- Forks: 29
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# css-inline
[](https://github.com/Stranger6667/css-inline/actions/workflows/build.yml)
[](https://crates.io/crates/css-inline)
[](https://docs.rs/css-inline)
[](https://app.codecov.io/github/Stranger6667/css-inline)
[](https://gitter.im/Stranger6667/css-inline)`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 crate transforms HTML like this:
```html
h1 { color:blue; }
Big Text
```
into:
```html
Big Text
```
- Uses reliable components from Mozilla's Servo project
- Inlines CSS from `style` and `link` tags
- Removes `style` and `link` tags
- Resolves external stylesheets (including local files)
- Optionally caches external stylesheets
- Works on Linux, Windows, and macOS
- Supports HTML5 & CSS3
- Bindings for [Python](https://github.com/Stranger6667/css-inline/tree/master/bindings/python), [Ruby](https://github.com/Stranger6667/css-inline/tree/master/bindings/ruby), [JavaScript](https://github.com/Stranger6667/css-inline/tree/master/bindings/javascript), [C](https://github.com/Stranger6667/css-inline/tree/master/bindings/c), and a [WebAssembly](https://github.com/Stranger6667/css-inline/tree/master/bindings/javascript/wasm) module to run in browsers.
- Command Line Interface## Playground
If you'd like to try `css-inline`, you can check the WebAssembly-powered [playground](https://css-inline.org/) to see the results instantly.
## Installation
To include it in your project, add the following line to the dependencies section in your project's `Cargo.toml` file:
```toml
[dependencies]
css-inline = "0.14"
```The Minimum Supported Rust Version is 1.65.
## Usage
```rust
const HTML: &str = r#"h1 { color:blue; }
Big Text
"#;
fn main() -> css_inline::Result<()> {
let inlined = css_inline::inline(HTML)?;
// Do something with inlined HTML, e.g. send an email
Ok(())
}
```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, preserving the original structure:
```rust
const FRAGMENT: &str = r#"Hello
who am i
"#;
const CSS: &str = r#"
p {
color: red;
}h1 {
color: blue;
}
"#;fn main() -> css_inline::Result<()> {
let inlined = css_inline::inline_fragment(FRAGMENT, CSS)?;
Ok(())
}
```### Configuration
`css-inline` can be configured by using `CSSInliner::options()` that implements the Builder pattern:
```rust
const HTML: &str = "...";fn main() -> css_inline::Result<()> {
let inliner = css_inline::CSSInliner::options()
.load_remote_stylesheets(false)
.build();
let inlined = inliner.inline(HTML)?;
// Do something with inlined HTML, e.g. send an email
Ok(())
}
```- `inline_style_tags`. Specifies whether to inline CSS from "style" tags. Default: `true`
- `keep_style_tags`. Specifies whether to keep "style" tags after inlining. Default: `false`
- `keep_link_tags`. Specifies whether to keep "link" tags after inlining. Default: `false`
- `base_url`. The base URL used to resolve relative URLs. If you'd like to load stylesheets from your filesystem, use the `file://` scheme. Default: `None`
- `load_remote_stylesheets`. Specifies whether remote stylesheets should be loaded. Default: `true`
- `cache`. Specifies cache for external stylesheets. Default: `None`
- `extra_css`. Extra CSS to be inlined. Default: `None`
- `preallocate_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: `32`You can also skip CSS inlining for an HTML tag by adding the `data-css-inline="ignore"` attribute to it:
```html
h1 { color:blue; }
Big Text
```
The `data-css-inline="ignore"` attribute also allows you to skip `link` and `style` tags:
```html
h1 { color:blue; }
Big Text
```
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:```html
h1 { color:blue; }
Big Text
```
Such tags will be kept in the resulting HTML even if the `keep_style_tags` option is set to `false`.
If you'd like to load stylesheets from your filesystem, use the `file://` scheme:
```rust
const HTML: &str = "...";fn main() -> css_inline::Result<()> {
let base_url = css_inline::Url::parse("file://styles/email/").expect("Invalid URL");
let inliner = css_inline::CSSInliner::options()
.base_url(Some(base_url))
.build();
let inlined = inliner.inline(HTML);
// Do something with inlined HTML, e.g. send an email
Ok(())
}
```For resolving remote stylesheets it is possible to implement a custom resolver:
```rust
#[derive(Debug, Default)]
pub struct CustomStylesheetResolver;impl css_inline::StylesheetResolver for CustomStylesheetResolver {
fn retrieve(&self, location: &str) -> css_inline::Result {
Err(self.unsupported("External stylesheets are not supported"))
}
}fn main() -> css_inline::Result<()> {
let inliner = css_inline::CSSInliner::options()
.resolver(std::sync::Arc::new(CustomStylesheetResolver))
.build();
Ok(())
}
```You can also cache external stylesheets to avoid excessive network requests:
```rust
use std::num::NonZeroUsize;#[cfg(feature = "stylesheet-cache")]
fn main() -> css_inline::Result<()> {
let inliner = css_inline::CSSInliner::options()
.cache(
// This is an LRU cache
css_inline::StylesheetCache::new(
NonZeroUsize::new(5).expect("Invalid cache size")
)
)
.build();
Ok(())
}// This block is here for testing purposes
#[cfg(not(feature = "stylesheet-cache"))]
fn main() -> css_inline::Result<()> {
Ok(())
}
```Caching is disabled by default.
## Performance
`css-inline` typically inlines HTML emails within hundreds of microseconds, though results may vary with input complexity.
Benchmarks for `css-inline==0.14.1`:
- Basic: **6.44 µs**, 230 bytes
- Realistic-1: **128.59 µs**, 8.58 KB
- Realistic-2: **81.44 µs**, 4.3 KB
- GitHub page: **224.89 ms**, 1.81 MBThese benchmarks, conducted using `rustc 1.78` on M1 Max, can be found in `css-inline/benches/inliner.rs`.
## Command Line Interface
### Installation
Install with `cargo`:
```text
cargo install css-inline
```### Usage
The following command inlines CSS in multiple documents in parallel. The resulting files will be saved
as `inlined.email1.html` and `inlined.email2.html`:```text
css-inline email1.html email2.html
```For full details of the options available, you can use the `--help` flag:
```text
css-inline --help
```## Further reading
If you're interested in learning how this library was created and how it works internally, check out these articles:
- [Rust crate](https://dygalo.dev/blog/rust-for-a-pythonista-2/)
- [Python bindings](https://dygalo.dev/blog/rust-for-a-pythonista-3/)## Support
If you have any questions or discussions related to this library, please join our [gitter](https://gitter.im/Stranger6667/css-inline)!
## License
This project is licensed under the terms of the MIT license.