Skip to content

Commit 2fb488b

Browse files
committed
feat: data-css-inline="ignore" attribute to ignore CSS inlining
Ref: #10
1 parent 9a10636 commit 2fb488b

File tree

8 files changed

+170
-3
lines changed

8 files changed

+170
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- `data-css-inline="ignore"` attribute to ignore CSS inlining. [#10](https://github.com/Stranger6667/css-inline/issues/10)
8+
59
## [0.8.3] - 2022-10-20
610

711
### Fixed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,34 @@ fn main() -> Result<(), css_inline::InlineError> {
8383
- `load_remote_stylesheets`. Whether remote stylesheets should be loaded or not. Default: `true`
8484
- `extra_css`. Additional CSS to inline. Default: `None`
8585

86+
If you'd like to skip CSS inlining for an HTML tag, add `data-css-inline="ignore"` attribute to it:
87+
88+
```html
89+
<head>
90+
<title>Test</title>
91+
<style>h1 { color:blue; }</style>
92+
</head>
93+
<body>
94+
<!-- The tag below won't receive additional styles -->
95+
<h1 data-css-inline="ignore">Big Text</h1>
96+
</body>
97+
</html>
98+
```
99+
100+
This attribute also allows you to skip `link` and `style` tags:
101+
102+
```html
103+
<head>
104+
<title>Test</title>
105+
<!-- Styles below are ignored -->
106+
<style data-css-inline="ignore">h1 { color:blue; }</style>
107+
</head>
108+
<body>
109+
<h1>Big Text</h1>
110+
</body>
111+
</html>
112+
```
113+
86114
## Bindings
87115

88116
There are bindings for Python and WebAssembly in the `bindings` directory.

bindings/python/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- `data-css-inline="ignore"` attribute to ignore CSS inlining. [#10](https://github.com/Stranger6667/css-inline/issues/10)
8+
59
## [0.8.4] - 2022-10-20
610

711
### Fixed

bindings/python/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ inliner = css_inline.CSSInliner(remove_style_tags=True)
8181
inliner.inline("...")
8282
```
8383

84+
If you'd like to skip CSS inlining for an HTML tag, add `data-css-inline="ignore"` attribute to it:
85+
86+
```html
87+
<head>
88+
<title>Test</title>
89+
<style>h1 { color:blue; }</style>
90+
</head>
91+
<body>
92+
<!-- The tag below won't receive additional styles -->
93+
<h1 data-css-inline="ignore">Big Text</h1>
94+
</body>
95+
</html>
96+
```
97+
98+
This attribute also allows you to skip `link` and `style` tags:
99+
100+
```html
101+
<head>
102+
<title>Test</title>
103+
<!-- Styles below are ignored -->
104+
<style data-css-inline="ignore">h1 { color:blue; }</style>
105+
</head>
106+
<body>
107+
<h1>Big Text</h1>
108+
</body>
109+
</html>
110+
```
111+
84112
Performance
85113
-----------
86114

bindings/wasm/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- `data-css-inline="ignore"` attribute to ignore CSS inlining. [#10](https://github.com/Stranger6667/css-inline/issues/10)
8+
59
## [0.8.2] - 2022-11-01
610

711
### Fixed

bindings/wasm/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,31 @@ var inlined = inline(
4343
// </html>
4444
// Do something with the inlined HTML, e.g. send an email
4545
```
46+
47+
If you'd like to skip CSS inlining for an HTML tag, add `data-css-inline="ignore"` attribute to it:
48+
49+
```html
50+
<head>
51+
<title>Test</title>
52+
<style>h1 { color:blue; }</style>
53+
</head>
54+
<body>
55+
<!-- The tag below won't receive additional styles -->
56+
<h1 data-css-inline="ignore">Big Text</h1>
57+
</body>
58+
</html>
59+
```
60+
61+
This attribute also allows you to skip `link` and `style` tags:
62+
63+
```html
64+
<head>
65+
<title>Test</title>
66+
<!-- Styles below are ignored -->
67+
<style data-css-inline="ignore">h1 { color:blue; }</style>
68+
</head>
69+
<body>
70+
<h1>Big Text</h1>
71+
</body>
72+
</html>
73+
```

css-inline/src/lib.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ impl Default for InlineOptions<'_> {
148148
}
149149

150150
type Result<T> = std::result::Result<T, InlineError>;
151+
const CSS_INLINE_ATTRIBUTE: &str = "data-css-inline";
151152

152153
/// Customizable CSS inliner.
153154
#[derive(Debug)]
@@ -246,8 +247,11 @@ impl<'a> CSSInliner<'a> {
246247
if self.options.inline_style_tags {
247248
for style_tag in document
248249
.select("style")
249-
.map_err(|_| error::InlineError::ParseError(Cow::from("Unknown error")))?
250+
.map_err(|_| InlineError::ParseError(Cow::from("Unknown error")))?
250251
{
252+
if let Some("ignore") = style_tag.attributes.borrow().get(CSS_INLINE_ATTRIBUTE) {
253+
continue;
254+
}
251255
if let Some(first_child) = style_tag.as_node().first_child() {
252256
if let Some(css_cell) = first_child.as_text() {
253257
process_css(&document, css_cell.borrow().as_str(), &mut styles);
@@ -275,7 +279,13 @@ impl<'a> CSSInliner<'a> {
275279
let mut links = document
276280
.select("link[rel~=stylesheet]")
277281
.map_err(|_| error::InlineError::ParseError(Cow::from("Unknown error")))?
278-
.filter_map(|link_tag| link_tag.attributes.borrow().get("href").map(str::to_string))
282+
.filter_map(|link_tag| {
283+
if let Some("ignore") = link_tag.attributes.borrow().get(CSS_INLINE_ATTRIBUTE) {
284+
None
285+
} else {
286+
link_tag.attributes.borrow().get("href").map(str::to_string)
287+
}
288+
})
279289
.filter(|link| !link.is_empty())
280290
.collect::<Vec<String>>();
281291
links.sort_unstable();
@@ -302,6 +312,10 @@ impl<'a> CSSInliner<'a> {
302312
.attributes
303313
.try_borrow_mut()
304314
{
315+
// Skip inlining for tags that have `data-css-inline="ignore"` attribute
316+
if let Some("ignore") = attributes.get(CSS_INLINE_ATTRIBUTE) {
317+
continue;
318+
}
305319
if let Some(existing_style) = attributes.get_mut("style") {
306320
*existing_style = merge_styles(existing_style, &styles)?;
307321
} else {
@@ -497,7 +511,7 @@ fn merge_styles(
497511
// NOTE: There will be no overflow as the new len is always smaller than the old one
498512
target.truncate(property.len() + 2);
499513
// And push the value
500-
target.push_str(value.trim())
514+
target.push_str(value.trim());
501515
}
502516
// No such rules exist - push the version with `!important` trimmed
503517
(Some(value), None) => final_styles.push(format!("{}: {}", property, value.trim())),

css-inline/tests/test_inlining.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,63 @@ p.footer { font-size: 1px}"#,
2020
)
2121
}
2222

23+
#[test]
24+
fn ignore_inlining_attribute_tag() {
25+
// When an HTML tag contains `data-css-inline="ignore"`
26+
assert_inlined!(
27+
style = "h1 { color:blue; }",
28+
body = r#"<h1 data-css-inline="ignore">Big Text</h1>"#,
29+
// Then it should be skipped
30+
expected = r#"<h1 data-css-inline="ignore">Big Text</h1>"#
31+
)
32+
}
33+
34+
#[test]
35+
fn ignore_inlining_attribute_style() {
36+
// When a `style` tag contains `data-css-inline="ignore"`
37+
let html = r#"
38+
<html>
39+
<head>
40+
<style type="text/css" data-css-inline="ignore">
41+
h1 { color: blue; }
42+
</style>
43+
</head>
44+
<body>
45+
<h1>Big Text</h1>
46+
</body>
47+
</html>"#;
48+
let result = inline(html).unwrap();
49+
// Then it should be skipped
50+
assert!(result.ends_with(
51+
r#"<body>
52+
<h1>Big Text</h1>
53+
54+
</body></html>"#
55+
))
56+
}
57+
58+
#[test]
59+
fn ignore_inlining_attribute_link() {
60+
// When a `link` tag contains `data-css-inline="ignore"`
61+
let html = r#"
62+
<html>
63+
<head>
64+
<link href="tests/external.css" rel="stylesheet" type="text/css" data-css-inline="ignore">
65+
</head>
66+
<body>
67+
<h1>Big Text</h1>
68+
</body>
69+
</html>"#;
70+
let result = inline(html).unwrap();
71+
// Then it should be skipped
72+
assert!(result.ends_with(
73+
r#"<body>
74+
<h1>Big Text</h1>
75+
76+
</body></html>"#
77+
))
78+
}
79+
2380
#[test]
2481
fn specificity_same_selector() {
2582
assert_inlined!(

0 commit comments

Comments
 (0)