css_inline 0.21.3 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +34 -35
- data/README.md +117 -87
- data/ext/css_inline/Cargo.lock +34 -35
- data/ext/css_inline/Cargo.toml +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7bdb9e863d0c4b1d333dbab94beb014c8884308dcc0d78731ed5706f8468a300
|
|
4
|
+
data.tar.gz: ce1097ee0ac4313ad964607c17fb31ead1abf79d082a8afc1e95a65fe25a100d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 172a49c2daa9b63e608e2919124e00edc48d3419cd9a96eece513c9990dc187f638764c08520bddb226e6a54068a4ef4792209be4fb32d245a89505936ea4a41
|
|
7
|
+
data.tar.gz: 70058af033f406d517bb14c064f55d79886824ab417fc7dc6cd93a75edeb8f6c5faeeb55af1ecdca8f7efac86098d04358c4d6fe90ae0fba0ef66c98fbdcca9b
|
data/Cargo.lock
CHANGED
|
@@ -154,9 +154,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
|
154
154
|
|
|
155
155
|
[[package]]
|
|
156
156
|
name = "css-inline"
|
|
157
|
-
version = "0.
|
|
157
|
+
version = "0.22.1"
|
|
158
158
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
159
|
-
checksum = "
|
|
159
|
+
checksum = "e50363b383b35fc4681129a12f93a653a58033cff464126a61c831c1563476ab"
|
|
160
160
|
dependencies = [
|
|
161
161
|
"cssparser",
|
|
162
162
|
"html5ever",
|
|
@@ -172,7 +172,7 @@ dependencies = [
|
|
|
172
172
|
|
|
173
173
|
[[package]]
|
|
174
174
|
name = "css-inline-ruby"
|
|
175
|
-
version = "0.
|
|
175
|
+
version = "0.22.1"
|
|
176
176
|
dependencies = [
|
|
177
177
|
"css-inline",
|
|
178
178
|
"magnus",
|
|
@@ -181,9 +181,9 @@ dependencies = [
|
|
|
181
181
|
|
|
182
182
|
[[package]]
|
|
183
183
|
name = "cssparser"
|
|
184
|
-
version = "0.
|
|
184
|
+
version = "0.38.0"
|
|
185
185
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
|
-
checksum = "
|
|
186
|
+
checksum = "11119743ad110e8c1bdccd930d7f5c30c99e5fc76a7b63ec9807e84eef0c5f59"
|
|
187
187
|
dependencies = [
|
|
188
188
|
"cssparser-macros",
|
|
189
189
|
"dtoa-short",
|
|
@@ -383,12 +383,13 @@ dependencies = [
|
|
|
383
383
|
|
|
384
384
|
[[package]]
|
|
385
385
|
name = "html5ever"
|
|
386
|
-
version = "0.
|
|
386
|
+
version = "0.40.1"
|
|
387
387
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
388
|
-
checksum = "
|
|
388
|
+
checksum = "456a1a377e608e555d22ddab27ac0114bc7a7b4199078108e34c2aeae6c9b130"
|
|
389
389
|
dependencies = [
|
|
390
390
|
"log",
|
|
391
391
|
"markup5ever",
|
|
392
|
+
"memchr",
|
|
392
393
|
]
|
|
393
394
|
|
|
394
395
|
[[package]]
|
|
@@ -695,9 +696,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
|
|
695
696
|
|
|
696
697
|
[[package]]
|
|
697
698
|
name = "magnus"
|
|
698
|
-
version = "0.
|
|
699
|
+
version = "0.9.1"
|
|
699
700
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
700
|
-
checksum = "
|
|
701
|
+
checksum = "4c01bef153b8d0f086991f0e166474a1d57b738221f9a9c11405d498ac95a44d"
|
|
701
702
|
dependencies = [
|
|
702
703
|
"magnus-macros",
|
|
703
704
|
"rb-sys",
|
|
@@ -707,9 +708,9 @@ dependencies = [
|
|
|
707
708
|
|
|
708
709
|
[[package]]
|
|
709
710
|
name = "magnus-macros"
|
|
710
|
-
version = "0.
|
|
711
|
+
version = "0.9.1"
|
|
711
712
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
712
|
-
checksum = "
|
|
713
|
+
checksum = "9dafde2eeb66f090e0f326112323eb8324b12cb32b5d1210e541d3df6b0ce77e"
|
|
713
714
|
dependencies = [
|
|
714
715
|
"proc-macro2",
|
|
715
716
|
"quote",
|
|
@@ -718,9 +719,9 @@ dependencies = [
|
|
|
718
719
|
|
|
719
720
|
[[package]]
|
|
720
721
|
name = "markup5ever"
|
|
721
|
-
version = "0.
|
|
722
|
+
version = "0.40.0"
|
|
722
723
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
723
|
-
checksum = "
|
|
724
|
+
checksum = "0ab3dc68ac4a0f5719e560136778c1ee716e296030d75dbd4484e37e39e3a842"
|
|
724
725
|
dependencies = [
|
|
725
726
|
"log",
|
|
726
727
|
"tendril",
|
|
@@ -803,9 +804,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|
|
803
804
|
|
|
804
805
|
[[package]]
|
|
805
806
|
name = "phf"
|
|
806
|
-
version = "0.
|
|
807
|
+
version = "0.14.0"
|
|
807
808
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
808
|
-
checksum = "
|
|
809
|
+
checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
|
|
809
810
|
dependencies = [
|
|
810
811
|
"phf_macros",
|
|
811
812
|
"phf_shared",
|
|
@@ -814,9 +815,9 @@ dependencies = [
|
|
|
814
815
|
|
|
815
816
|
[[package]]
|
|
816
817
|
name = "phf_codegen"
|
|
817
|
-
version = "0.
|
|
818
|
+
version = "0.14.0"
|
|
818
819
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
819
|
-
checksum = "
|
|
820
|
+
checksum = "41b585a510fb76fdebead6897982ef2a03a21d8e6cbcca904999742a4afc6ffe"
|
|
820
821
|
dependencies = [
|
|
821
822
|
"phf_generator",
|
|
822
823
|
"phf_shared",
|
|
@@ -824,9 +825,9 @@ dependencies = [
|
|
|
824
825
|
|
|
825
826
|
[[package]]
|
|
826
827
|
name = "phf_generator"
|
|
827
|
-
version = "0.
|
|
828
|
+
version = "0.14.0"
|
|
828
829
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
829
|
-
checksum = "
|
|
830
|
+
checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100"
|
|
830
831
|
dependencies = [
|
|
831
832
|
"fastrand",
|
|
832
833
|
"phf_shared",
|
|
@@ -834,9 +835,9 @@ dependencies = [
|
|
|
834
835
|
|
|
835
836
|
[[package]]
|
|
836
837
|
name = "phf_macros"
|
|
837
|
-
version = "0.
|
|
838
|
+
version = "0.14.0"
|
|
838
839
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
839
|
-
checksum = "
|
|
840
|
+
checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085"
|
|
840
841
|
dependencies = [
|
|
841
842
|
"phf_generator",
|
|
842
843
|
"phf_shared",
|
|
@@ -847,9 +848,9 @@ dependencies = [
|
|
|
847
848
|
|
|
848
849
|
[[package]]
|
|
849
850
|
name = "phf_shared"
|
|
850
|
-
version = "0.
|
|
851
|
+
version = "0.14.0"
|
|
851
852
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
852
|
-
checksum = "
|
|
853
|
+
checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89"
|
|
853
854
|
dependencies = [
|
|
854
855
|
"siphasher",
|
|
855
856
|
]
|
|
@@ -1193,17 +1194,15 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
1193
1194
|
|
|
1194
1195
|
[[package]]
|
|
1195
1196
|
name = "selectors"
|
|
1196
|
-
version = "0.
|
|
1197
|
+
version = "0.41.0"
|
|
1197
1198
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1198
|
-
checksum = "
|
|
1199
|
+
checksum = "8322aebea94a6cc288ff884e8a49bdbceef60206c400c6c46d22e62fc4fd91a6"
|
|
1199
1200
|
dependencies = [
|
|
1200
1201
|
"bitflags",
|
|
1201
1202
|
"cssparser",
|
|
1202
1203
|
"derive_more",
|
|
1203
1204
|
"log",
|
|
1204
1205
|
"new_debug_unreachable",
|
|
1205
|
-
"phf",
|
|
1206
|
-
"phf_codegen",
|
|
1207
1206
|
"precomputed-hash",
|
|
1208
1207
|
"rustc-hash",
|
|
1209
1208
|
"servo_arc",
|
|
@@ -1279,9 +1278,9 @@ dependencies = [
|
|
|
1279
1278
|
|
|
1280
1279
|
[[package]]
|
|
1281
1280
|
name = "servo_arc"
|
|
1282
|
-
version = "0.
|
|
1281
|
+
version = "0.5.0"
|
|
1283
1282
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1284
|
-
checksum = "
|
|
1283
|
+
checksum = "b4eceb519ec34d8290aaf6e46f435102f2bfa63f22b05a144fb16ab266d3b198"
|
|
1285
1284
|
dependencies = [
|
|
1286
1285
|
"stable_deref_trait",
|
|
1287
1286
|
]
|
|
@@ -1334,9 +1333,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
|
1334
1333
|
|
|
1335
1334
|
[[package]]
|
|
1336
1335
|
name = "string_cache"
|
|
1337
|
-
version = "0.
|
|
1336
|
+
version = "0.11.0"
|
|
1338
1337
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1339
|
-
checksum = "
|
|
1338
|
+
checksum = "ffa8a5dbe8b3f0bbe29d4c3225daafaeead63afdc1b65fc4c01a1384166038e6"
|
|
1340
1339
|
dependencies = [
|
|
1341
1340
|
"new_debug_unreachable",
|
|
1342
1341
|
"parking_lot",
|
|
@@ -1346,9 +1345,9 @@ dependencies = [
|
|
|
1346
1345
|
|
|
1347
1346
|
[[package]]
|
|
1348
1347
|
name = "string_cache_codegen"
|
|
1349
|
-
version = "0.
|
|
1348
|
+
version = "0.11.2"
|
|
1350
1349
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1351
|
-
checksum = "
|
|
1350
|
+
checksum = "928dcdf75e47626b3617a976ec205d9f057584c371c1f23b782129268d0e6edc"
|
|
1352
1351
|
dependencies = [
|
|
1353
1352
|
"phf_generator",
|
|
1354
1353
|
"phf_shared",
|
|
@@ -1670,9 +1669,9 @@ dependencies = [
|
|
|
1670
1669
|
|
|
1671
1670
|
[[package]]
|
|
1672
1671
|
name = "web_atoms"
|
|
1673
|
-
version = "0.
|
|
1672
|
+
version = "0.3.0"
|
|
1674
1673
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1675
|
-
checksum = "
|
|
1674
|
+
checksum = "7572660c8890448ba236b7376f27e389c6a7e1c70195622faced601f855c0ada"
|
|
1676
1675
|
dependencies = [
|
|
1677
1676
|
"phf",
|
|
1678
1677
|
"phf_codegen",
|
data/README.md
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
[<img alt="codecov.io" src="https://img.shields.io/codecov/c/gh/Stranger6667/css-inline?logo=codecov&style=flat-square&token=tOzvV4kDY0" height="20">](https://app.codecov.io/github/Stranger6667/css-inline)
|
|
6
6
|
[<img alt="gitter" src="https://img.shields.io/gitter/room/Stranger6667/css-inline?style=flat-square" height="20">](https://gitter.im/Stranger6667/css-inline)
|
|
7
7
|
|
|
8
|
-
`css_inline`
|
|
8
|
+
`css_inline` moves CSS from `<style>` and `<link>` tags into HTML `style` attributes.
|
|
9
|
+
Use it to prepare HTML emails or to embed HTML into third-party web pages.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
For instance, the library transforms HTML like this:
|
|
11
|
+
It turns this HTML:
|
|
13
12
|
|
|
14
13
|
```html
|
|
15
14
|
<html>
|
|
@@ -28,36 +27,45 @@ into:
|
|
|
28
27
|
<html>
|
|
29
28
|
<head></head>
|
|
30
29
|
<body>
|
|
31
|
-
<h1 style="color:blue;">Big Text</h1>
|
|
30
|
+
<h1 style="color: blue;">Big Text</h1>
|
|
32
31
|
</body>
|
|
33
32
|
</html>
|
|
34
33
|
```
|
|
35
34
|
|
|
36
|
-
-
|
|
35
|
+
- Parses and matches CSS with components from Mozilla's Servo project
|
|
37
36
|
- Inlines CSS from `style` and `link` tags
|
|
38
37
|
- Removes `style` and `link` tags
|
|
39
38
|
- Resolves external stylesheets (including local files)
|
|
40
|
-
-
|
|
39
|
+
- Caches external stylesheets (opt-in)
|
|
41
40
|
- Can process multiple documents in parallel
|
|
42
41
|
- Works on Linux, Windows, and macOS
|
|
43
42
|
- Supports HTML5 & CSS3
|
|
44
|
-
- Tested on Ruby 3.2, 3.3,
|
|
43
|
+
- Tested on Ruby 3.2, 3.3, 3.4, and 4.0
|
|
45
44
|
|
|
46
45
|
## Playground
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
Try `css-inline` in the WebAssembly-powered [playground](https://css-inline.org/).
|
|
49
48
|
|
|
50
49
|
## Installation
|
|
51
50
|
|
|
52
|
-
Add this line to your application's `Gemfile`:
|
|
51
|
+
Add this line to your application's `Gemfile` and run `bundle install`:
|
|
53
52
|
|
|
54
|
-
```
|
|
53
|
+
```ruby
|
|
55
54
|
gem 'css_inline'
|
|
56
55
|
```
|
|
57
56
|
|
|
57
|
+
Or install it directly:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
gem install css_inline
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
RubyGems ships precompiled native gems for Ruby 3.2 to 4.0 on Linux (x86_64, aarch64, glibc and musl), macOS (x86_64, arm64) and Windows (x64 UCRT).
|
|
64
|
+
On other platforms, `gem install` builds the extension from source and needs a Rust toolchain.
|
|
65
|
+
|
|
58
66
|
## Usage
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
Inline CSS in an HTML document:
|
|
61
69
|
|
|
62
70
|
```ruby
|
|
63
71
|
require 'css_inline'
|
|
@@ -66,39 +74,39 @@ html = "<html><head><style>h1 { color:blue; }</style></head><body><h1>Big Text</
|
|
|
66
74
|
inlined = CSSInline.inline(html)
|
|
67
75
|
|
|
68
76
|
puts inlined
|
|
69
|
-
#
|
|
77
|
+
# <html><head></head><body><h1 style="color: blue;">Big Text</h1></body></html>
|
|
70
78
|
```
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
`css-inline` adds missing `html`, `head` and `body` tags, so the output is a valid HTML document.
|
|
73
81
|
|
|
74
|
-
|
|
82
|
+
To inline CSS into an HTML fragment, use `inline_fragment`. It strips structural tags (`<html>`, `<head>`, `<body>`) from the output and keeps their contents. Use `CSSInline.inline` to keep the full document structure:
|
|
75
83
|
|
|
76
84
|
```ruby
|
|
77
85
|
require 'css_inline'
|
|
78
86
|
|
|
79
|
-
fragment =
|
|
80
|
-
<main>
|
|
81
|
-
<h1>Hello</h1>
|
|
82
|
-
<section>
|
|
83
|
-
<p>who am i</p>
|
|
84
|
-
</section>
|
|
85
|
-
</main>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
css =
|
|
89
|
-
p {
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
h1 {
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
87
|
+
fragment = <<~HTML
|
|
88
|
+
<main>
|
|
89
|
+
<h1>Hello</h1>
|
|
90
|
+
<section>
|
|
91
|
+
<p>who am i</p>
|
|
92
|
+
</section>
|
|
93
|
+
</main>
|
|
94
|
+
HTML
|
|
95
|
+
|
|
96
|
+
css = <<~CSS
|
|
97
|
+
p {
|
|
98
|
+
color: red;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
h1 {
|
|
102
|
+
color: blue;
|
|
103
|
+
}
|
|
104
|
+
CSS
|
|
97
105
|
|
|
98
106
|
inlined = CSSInline.inline_fragment(fragment, css)
|
|
99
107
|
|
|
100
108
|
puts inlined
|
|
101
|
-
#
|
|
109
|
+
# Output:
|
|
102
110
|
# <main>
|
|
103
111
|
# <h1 style="color: blue;">Hello</h1>
|
|
104
112
|
# <section>
|
|
@@ -107,23 +115,27 @@ puts inlined
|
|
|
107
115
|
# </main>
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
|
|
111
|
-
This feature allows for concurrent processing of several inputs, significantly improving performance when dealing with a large number of documents.
|
|
118
|
+
To inline many documents in parallel, use `inline_many` and `inline_many_fragments`:
|
|
112
119
|
|
|
113
120
|
```ruby
|
|
114
121
|
require 'css_inline'
|
|
115
122
|
|
|
116
123
|
inlined = CSSInline.inline_many(["...", "..."])
|
|
124
|
+
inlined = CSSInline.inline_many_fragments(["<h1>...</h1>", "<p>...</p>"], ["h1 { color: blue; }", "p { color: red; }"])
|
|
117
125
|
```
|
|
118
126
|
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
`inline_many_fragments` pairs HTML and CSS by index.
|
|
128
|
+
|
|
129
|
+
**Warning**: pass arrays of equal length. If they differ, `inline_many_fragments` drops the extra items of the longer array without an error.
|
|
121
130
|
|
|
122
|
-
|
|
131
|
+
If one input fails, the whole call raises and returns no results.
|
|
132
|
+
|
|
133
|
+
Both functions process inputs on a Rust thread pool ([rayon](https://github.com/rayon-rs/rayon)), one thread per CPU core.
|
|
134
|
+
Ruby threads can't run this CPU-bound work in parallel because of the Global VM Lock, so `inline_many` gains over a Ruby loop only on a multicore machine.
|
|
123
135
|
|
|
124
136
|
## Configuration
|
|
125
137
|
|
|
126
|
-
|
|
138
|
+
Pass options as keyword arguments to `CSSInline::CSSInliner.new`:
|
|
127
139
|
|
|
128
140
|
```ruby
|
|
129
141
|
require 'css_inline'
|
|
@@ -132,21 +144,25 @@ inliner = CSSInline::CSSInliner.new(keep_style_tags: true)
|
|
|
132
144
|
inliner.inline("...")
|
|
133
145
|
```
|
|
134
146
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
- `
|
|
140
|
-
- `
|
|
141
|
-
- `
|
|
142
|
-
- `
|
|
143
|
-
- `
|
|
144
|
-
- `
|
|
145
|
-
- `
|
|
146
|
-
- `
|
|
147
|
-
- `
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
A `CSSInliner` instance has the same four methods as the module: `inline`, `inline_fragment`, `inline_many` and `inline_many_fragments`.
|
|
148
|
+
Reuse one instance to share its stylesheet cache across calls.
|
|
149
|
+
The module functions accept the same keyword arguments, for example `CSSInline.inline(html, keep_style_tags: true)`.
|
|
150
|
+
|
|
151
|
+
- `inline_style_tags`. Inline CSS from `style` tags. Default: `true`
|
|
152
|
+
- `keep_style_tags`. Keep `style` tags after inlining. Default: `false`
|
|
153
|
+
- `keep_link_tags`. Keep `link` tags after inlining. Default: `false`
|
|
154
|
+
- `keep_at_rules`. Keep at-rules (starting with `@`) after inlining. Default: `false`
|
|
155
|
+
- `minify_css`. Remove trailing semicolons and spaces between properties and values. Default: `false`
|
|
156
|
+
- `base_url`. Base URL for resolving relative URLs. Use the `file://` scheme to load stylesheets from the filesystem. Default: `nil`
|
|
157
|
+
- `load_remote_stylesheets`. Load stylesheets from `link` tags, over the network or from `file://` paths. Default: `true`
|
|
158
|
+
- `cache`. Cache for external stylesheets, for example `CSSInline::StylesheetCache.new(size: 5)`. Default: `nil`
|
|
159
|
+
- `extra_css`. Extra CSS to inline. Default: `nil`
|
|
160
|
+
- `preallocate_node_capacity`. **Advanced**. Number of HTML nodes to preallocate during parsing. Set it to your expected node count to avoid reallocations. Default: `32`
|
|
161
|
+
- `remove_inlined_selectors`. Remove inlined selectors from `<style>` blocks. Default: `false`
|
|
162
|
+
- `apply_width_attributes`. Add `width` HTML attributes from CSS `width` properties on `table`, `td`, `th` and `img`. Default: `false`
|
|
163
|
+
- `apply_height_attributes`. Add `height` HTML attributes from CSS `height` properties on `table`, `td`, `th` and `img`. Default: `false`
|
|
164
|
+
|
|
165
|
+
To skip CSS inlining for an HTML tag, add the `data-css-inline="ignore"` attribute to it:
|
|
150
166
|
|
|
151
167
|
```html
|
|
152
168
|
<head>
|
|
@@ -158,7 +174,7 @@ You can also skip CSS inlining for an HTML tag by adding the `data-css-inline="i
|
|
|
158
174
|
</body>
|
|
159
175
|
```
|
|
160
176
|
|
|
161
|
-
The
|
|
177
|
+
The same attribute on a `link` or `style` tag skips that stylesheet:
|
|
162
178
|
|
|
163
179
|
```html
|
|
164
180
|
<head>
|
|
@@ -170,9 +186,9 @@ The `data-css-inline="ignore"` attribute also allows you to skip `link` and `sty
|
|
|
170
186
|
</body>
|
|
171
187
|
```
|
|
172
188
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
189
|
+
To keep a `style` tag in the output, add the `data-css-inline="keep"` attribute.
|
|
190
|
+
Use it to keep `@media` queries for responsive emails in separate `style` tags.
|
|
191
|
+
`css-inline` keeps such tags even when `keep_style_tags` is `false`.
|
|
176
192
|
|
|
177
193
|
```html
|
|
178
194
|
<head>
|
|
@@ -184,14 +200,13 @@ Such tags will be kept in the resulting HTML even if the `keep_style_tags` optio
|
|
|
184
200
|
</body>
|
|
185
201
|
```
|
|
186
202
|
|
|
187
|
-
Another
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Such tags will be kept in the resulting HTML even if the `keep_style_tags` option is explicitly set to `false`.
|
|
203
|
+
Another way is the `keep_at_rules` option. At-rules can't go into `style` attributes, so `css-inline` removes them by default.
|
|
204
|
+
With `keep_at_rules: true`, it inlines regular rules and keeps at-rules, such as `@media` queries, in `style` tags.
|
|
205
|
+
It keeps these tags even when `keep_style_tags` is `false`.
|
|
191
206
|
|
|
192
207
|
```html
|
|
193
208
|
<head>
|
|
194
|
-
<!-- With keep_at_rules
|
|
209
|
+
<!-- With keep_at_rules: true, "color:blue" will get inlined into <h1> but @media will be kept in <style> -->
|
|
195
210
|
<style>h1 { color: blue; } @media (max-width: 600px) { h1 { font-size: 18px; } }</style>
|
|
196
211
|
</head>
|
|
197
212
|
<body>
|
|
@@ -199,12 +214,11 @@ Such tags will be kept in the resulting HTML even if the `keep_style_tags` optio
|
|
|
199
214
|
</body>
|
|
200
215
|
```
|
|
201
216
|
|
|
202
|
-
|
|
203
|
-
and spaces between properties and values.
|
|
217
|
+
With `minify_css: true`, `css-inline` removes trailing semicolons and spaces between properties and values in inlined styles.
|
|
204
218
|
|
|
205
219
|
```html
|
|
206
220
|
<head>
|
|
207
|
-
<!-- With minify_css
|
|
221
|
+
<!-- With minify_css: true, the <h1> will have `style="color:blue;font-weight:bold"` -->
|
|
208
222
|
<style>h1 { color: blue; font-weight: bold; }</style>
|
|
209
223
|
</head>
|
|
210
224
|
<body>
|
|
@@ -212,17 +226,20 @@ and spaces between properties and values.
|
|
|
212
226
|
</body>
|
|
213
227
|
```
|
|
214
228
|
|
|
215
|
-
|
|
229
|
+
To load stylesheets from the filesystem, use the `file://` scheme.
|
|
230
|
+
`css-inline` treats a `file://` URL without a third slash, such as `file://styles/email/`, as a path relative to the current working directory.
|
|
231
|
+
Standard URL parsers read `styles` there as a host, so this form is specific to `css-inline`.
|
|
232
|
+
For an absolute path, use three slashes: `file:///path/to/styles/`.
|
|
216
233
|
|
|
217
234
|
```ruby
|
|
218
235
|
require 'css_inline'
|
|
219
236
|
|
|
220
|
-
# styles/email
|
|
237
|
+
# Loads stylesheets from ./styles/email/
|
|
221
238
|
inliner = CSSInline::CSSInliner.new(base_url: "file://styles/email/")
|
|
222
239
|
inliner.inline("...")
|
|
223
240
|
```
|
|
224
241
|
|
|
225
|
-
|
|
242
|
+
To avoid repeated network requests, cache external stylesheets:
|
|
226
243
|
|
|
227
244
|
```ruby
|
|
228
245
|
require 'css_inline'
|
|
@@ -233,32 +250,45 @@ inliner = CSSInline::CSSInliner.new(
|
|
|
233
250
|
inliner.inline("...")
|
|
234
251
|
```
|
|
235
252
|
|
|
236
|
-
|
|
253
|
+
The cache covers every `link` stylesheet, `file://` included. `size` is the number of stylesheets to keep (default: `8`). When the cache is full, it evicts the least recently used stylesheet.
|
|
254
|
+
Caching is off by default.
|
|
237
255
|
|
|
238
|
-
##
|
|
256
|
+
## Errors
|
|
239
257
|
|
|
240
|
-
|
|
241
|
-
Performance benchmarks show 50-100x faster execution than `roadie` and `premailer`.
|
|
258
|
+
All functions raise `ArgumentError` when they can't load a stylesheet (missing file, network error), can't parse one, or get an invalid `base_url`:
|
|
242
259
|
|
|
243
|
-
|
|
260
|
+
```ruby
|
|
261
|
+
require 'css_inline'
|
|
244
262
|
|
|
245
|
-
|
|
263
|
+
begin
|
|
264
|
+
CSSInline.inline('<link rel="stylesheet" href="missing.css"><h1>Hi</h1>')
|
|
265
|
+
rescue ArgumentError => e
|
|
266
|
+
puts e.message
|
|
267
|
+
# Missing stylesheet file: missing.css
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Performance
|
|
272
|
+
|
|
273
|
+
`css_inline` runs 8.1x to 354x faster than `roadie` and 57x to 123x faster than `premailer` on these documents:
|
|
274
|
+
|
|
275
|
+
| | Size | `css_inline 0.22.0` | `roadie 5.2.1` | `premailer 1.27.0` |
|
|
246
276
|
|-------------------|---------|---------------------|-------------------------|-------------------------|
|
|
247
|
-
| Basic usage | 230 B |
|
|
248
|
-
| Realistic email 1 | 8.58 KB |
|
|
249
|
-
| Realistic email 2 | 4.
|
|
250
|
-
| GitHub Page | 1.81 MB |
|
|
277
|
+
| Basic usage | 230 B | 5.84 µs | 168.88 µs (**28.92x**) | 331.07 µs (**56.69x**) |
|
|
278
|
+
| Realistic email 1 | 8.58 KB | 87.66 µs | 713.78 µs (**8.14x**) | 6.95 ms (**79.28x**) |
|
|
279
|
+
| Realistic email 2 | 4.30 KB | 50.45 µs | 1.98 ms (**39.25x**) | ERROR |
|
|
280
|
+
| GitHub Page | 1.81 MB | 19.01 ms | 6.73 s (**354.02x**) | 2.34 s (**123.09x**) |
|
|
251
281
|
|
|
252
|
-
|
|
253
|
-
The results displayed above were measured using stable `rustc 1.91` on Ruby `3.4.7`.
|
|
282
|
+
`premailer` fails on "Realistic email 2" with `ArgumentError: Cannot parse 0 calc((100% - 500px) / 2)`.
|
|
254
283
|
|
|
255
|
-
|
|
284
|
+
Inputs come from [`benchmarks/benchmarks.json`](https://github.com/Stranger6667/css-inline/blob/master/benchmarks/benchmarks.json): Basic usage is `simple`, Realistic email 1 and 2 are `big_email_1` and `big_email_2`, GitHub Page is `big_page`.
|
|
285
|
+
The benchmark code is in [`test/bench.rb`](https://github.com/Stranger6667/css-inline/blob/master/bindings/ruby/test/bench.rb) and uses [`benchmark-ips`](https://github.com/evanphx/benchmark-ips) (5 s per case; `roadie` completes one run on the GitHub page in that time).
|
|
286
|
+
We measured these results with stable `rustc 1.99` on Ruby `3.4.8`, Ryzen 9 9950X.
|
|
256
287
|
|
|
257
|
-
|
|
288
|
+
## Further reading
|
|
258
289
|
|
|
259
|
-
- [Rust crate](https://dygalo.dev/blog/rust-for-a-pythonista-2/)
|
|
260
|
-
- [Python bindings](https://dygalo.dev/blog/rust-for-a-pythonista-3/)
|
|
290
|
+
- [How the Rust crate works](https://dygalo.dev/blog/rust-for-a-pythonista-2/)
|
|
261
291
|
|
|
262
292
|
## License
|
|
263
293
|
|
|
264
|
-
|
|
294
|
+
[MIT license](https://opensource.org/licenses/MIT).
|
data/ext/css_inline/Cargo.lock
CHANGED
|
@@ -154,9 +154,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
|
154
154
|
|
|
155
155
|
[[package]]
|
|
156
156
|
name = "css-inline"
|
|
157
|
-
version = "0.
|
|
157
|
+
version = "0.22.1"
|
|
158
158
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
159
|
-
checksum = "
|
|
159
|
+
checksum = "e50363b383b35fc4681129a12f93a653a58033cff464126a61c831c1563476ab"
|
|
160
160
|
dependencies = [
|
|
161
161
|
"cssparser",
|
|
162
162
|
"html5ever",
|
|
@@ -172,7 +172,7 @@ dependencies = [
|
|
|
172
172
|
|
|
173
173
|
[[package]]
|
|
174
174
|
name = "css-inline-ruby"
|
|
175
|
-
version = "0.
|
|
175
|
+
version = "0.22.1"
|
|
176
176
|
dependencies = [
|
|
177
177
|
"css-inline",
|
|
178
178
|
"magnus",
|
|
@@ -181,9 +181,9 @@ dependencies = [
|
|
|
181
181
|
|
|
182
182
|
[[package]]
|
|
183
183
|
name = "cssparser"
|
|
184
|
-
version = "0.
|
|
184
|
+
version = "0.38.0"
|
|
185
185
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
|
-
checksum = "
|
|
186
|
+
checksum = "11119743ad110e8c1bdccd930d7f5c30c99e5fc76a7b63ec9807e84eef0c5f59"
|
|
187
187
|
dependencies = [
|
|
188
188
|
"cssparser-macros",
|
|
189
189
|
"dtoa-short",
|
|
@@ -383,12 +383,13 @@ dependencies = [
|
|
|
383
383
|
|
|
384
384
|
[[package]]
|
|
385
385
|
name = "html5ever"
|
|
386
|
-
version = "0.
|
|
386
|
+
version = "0.40.1"
|
|
387
387
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
388
|
-
checksum = "
|
|
388
|
+
checksum = "456a1a377e608e555d22ddab27ac0114bc7a7b4199078108e34c2aeae6c9b130"
|
|
389
389
|
dependencies = [
|
|
390
390
|
"log",
|
|
391
391
|
"markup5ever",
|
|
392
|
+
"memchr",
|
|
392
393
|
]
|
|
393
394
|
|
|
394
395
|
[[package]]
|
|
@@ -695,9 +696,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
|
|
695
696
|
|
|
696
697
|
[[package]]
|
|
697
698
|
name = "magnus"
|
|
698
|
-
version = "0.
|
|
699
|
+
version = "0.9.1"
|
|
699
700
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
700
|
-
checksum = "
|
|
701
|
+
checksum = "4c01bef153b8d0f086991f0e166474a1d57b738221f9a9c11405d498ac95a44d"
|
|
701
702
|
dependencies = [
|
|
702
703
|
"magnus-macros",
|
|
703
704
|
"rb-sys",
|
|
@@ -707,9 +708,9 @@ dependencies = [
|
|
|
707
708
|
|
|
708
709
|
[[package]]
|
|
709
710
|
name = "magnus-macros"
|
|
710
|
-
version = "0.
|
|
711
|
+
version = "0.9.1"
|
|
711
712
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
712
|
-
checksum = "
|
|
713
|
+
checksum = "9dafde2eeb66f090e0f326112323eb8324b12cb32b5d1210e541d3df6b0ce77e"
|
|
713
714
|
dependencies = [
|
|
714
715
|
"proc-macro2",
|
|
715
716
|
"quote",
|
|
@@ -718,9 +719,9 @@ dependencies = [
|
|
|
718
719
|
|
|
719
720
|
[[package]]
|
|
720
721
|
name = "markup5ever"
|
|
721
|
-
version = "0.
|
|
722
|
+
version = "0.40.0"
|
|
722
723
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
723
|
-
checksum = "
|
|
724
|
+
checksum = "0ab3dc68ac4a0f5719e560136778c1ee716e296030d75dbd4484e37e39e3a842"
|
|
724
725
|
dependencies = [
|
|
725
726
|
"log",
|
|
726
727
|
"tendril",
|
|
@@ -803,9 +804,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|
|
803
804
|
|
|
804
805
|
[[package]]
|
|
805
806
|
name = "phf"
|
|
806
|
-
version = "0.
|
|
807
|
+
version = "0.14.0"
|
|
807
808
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
808
|
-
checksum = "
|
|
809
|
+
checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
|
|
809
810
|
dependencies = [
|
|
810
811
|
"phf_macros",
|
|
811
812
|
"phf_shared",
|
|
@@ -814,9 +815,9 @@ dependencies = [
|
|
|
814
815
|
|
|
815
816
|
[[package]]
|
|
816
817
|
name = "phf_codegen"
|
|
817
|
-
version = "0.
|
|
818
|
+
version = "0.14.0"
|
|
818
819
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
819
|
-
checksum = "
|
|
820
|
+
checksum = "41b585a510fb76fdebead6897982ef2a03a21d8e6cbcca904999742a4afc6ffe"
|
|
820
821
|
dependencies = [
|
|
821
822
|
"phf_generator",
|
|
822
823
|
"phf_shared",
|
|
@@ -824,9 +825,9 @@ dependencies = [
|
|
|
824
825
|
|
|
825
826
|
[[package]]
|
|
826
827
|
name = "phf_generator"
|
|
827
|
-
version = "0.
|
|
828
|
+
version = "0.14.0"
|
|
828
829
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
829
|
-
checksum = "
|
|
830
|
+
checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100"
|
|
830
831
|
dependencies = [
|
|
831
832
|
"fastrand",
|
|
832
833
|
"phf_shared",
|
|
@@ -834,9 +835,9 @@ dependencies = [
|
|
|
834
835
|
|
|
835
836
|
[[package]]
|
|
836
837
|
name = "phf_macros"
|
|
837
|
-
version = "0.
|
|
838
|
+
version = "0.14.0"
|
|
838
839
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
839
|
-
checksum = "
|
|
840
|
+
checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085"
|
|
840
841
|
dependencies = [
|
|
841
842
|
"phf_generator",
|
|
842
843
|
"phf_shared",
|
|
@@ -847,9 +848,9 @@ dependencies = [
|
|
|
847
848
|
|
|
848
849
|
[[package]]
|
|
849
850
|
name = "phf_shared"
|
|
850
|
-
version = "0.
|
|
851
|
+
version = "0.14.0"
|
|
851
852
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
852
|
-
checksum = "
|
|
853
|
+
checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89"
|
|
853
854
|
dependencies = [
|
|
854
855
|
"siphasher",
|
|
855
856
|
]
|
|
@@ -1193,17 +1194,15 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
1193
1194
|
|
|
1194
1195
|
[[package]]
|
|
1195
1196
|
name = "selectors"
|
|
1196
|
-
version = "0.
|
|
1197
|
+
version = "0.41.0"
|
|
1197
1198
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1198
|
-
checksum = "
|
|
1199
|
+
checksum = "8322aebea94a6cc288ff884e8a49bdbceef60206c400c6c46d22e62fc4fd91a6"
|
|
1199
1200
|
dependencies = [
|
|
1200
1201
|
"bitflags",
|
|
1201
1202
|
"cssparser",
|
|
1202
1203
|
"derive_more",
|
|
1203
1204
|
"log",
|
|
1204
1205
|
"new_debug_unreachable",
|
|
1205
|
-
"phf",
|
|
1206
|
-
"phf_codegen",
|
|
1207
1206
|
"precomputed-hash",
|
|
1208
1207
|
"rustc-hash",
|
|
1209
1208
|
"servo_arc",
|
|
@@ -1279,9 +1278,9 @@ dependencies = [
|
|
|
1279
1278
|
|
|
1280
1279
|
[[package]]
|
|
1281
1280
|
name = "servo_arc"
|
|
1282
|
-
version = "0.
|
|
1281
|
+
version = "0.5.0"
|
|
1283
1282
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1284
|
-
checksum = "
|
|
1283
|
+
checksum = "b4eceb519ec34d8290aaf6e46f435102f2bfa63f22b05a144fb16ab266d3b198"
|
|
1285
1284
|
dependencies = [
|
|
1286
1285
|
"stable_deref_trait",
|
|
1287
1286
|
]
|
|
@@ -1334,9 +1333,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
|
1334
1333
|
|
|
1335
1334
|
[[package]]
|
|
1336
1335
|
name = "string_cache"
|
|
1337
|
-
version = "0.
|
|
1336
|
+
version = "0.11.0"
|
|
1338
1337
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1339
|
-
checksum = "
|
|
1338
|
+
checksum = "ffa8a5dbe8b3f0bbe29d4c3225daafaeead63afdc1b65fc4c01a1384166038e6"
|
|
1340
1339
|
dependencies = [
|
|
1341
1340
|
"new_debug_unreachable",
|
|
1342
1341
|
"parking_lot",
|
|
@@ -1346,9 +1345,9 @@ dependencies = [
|
|
|
1346
1345
|
|
|
1347
1346
|
[[package]]
|
|
1348
1347
|
name = "string_cache_codegen"
|
|
1349
|
-
version = "0.
|
|
1348
|
+
version = "0.11.2"
|
|
1350
1349
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1351
|
-
checksum = "
|
|
1350
|
+
checksum = "928dcdf75e47626b3617a976ec205d9f057584c371c1f23b782129268d0e6edc"
|
|
1352
1351
|
dependencies = [
|
|
1353
1352
|
"phf_generator",
|
|
1354
1353
|
"phf_shared",
|
|
@@ -1670,9 +1669,9 @@ dependencies = [
|
|
|
1670
1669
|
|
|
1671
1670
|
[[package]]
|
|
1672
1671
|
name = "web_atoms"
|
|
1673
|
-
version = "0.
|
|
1672
|
+
version = "0.3.0"
|
|
1674
1673
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1675
|
-
checksum = "
|
|
1674
|
+
checksum = "7572660c8890448ba236b7376f27e389c6a7e1c70195622faced601f855c0ada"
|
|
1676
1675
|
dependencies = [
|
|
1677
1676
|
"phf",
|
|
1678
1677
|
"phf_codegen",
|
data/ext/css_inline/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "css-inline-ruby"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.22.1"
|
|
4
4
|
authors = ["Dmitry Dygalo <dmitry@dygalo.dev>"]
|
|
5
5
|
edition = "2024"
|
|
6
6
|
readme = "README.rdoc"
|
|
@@ -16,10 +16,10 @@ name = "css_inline"
|
|
|
16
16
|
crate-type = ["cdylib"]
|
|
17
17
|
|
|
18
18
|
[dependencies]
|
|
19
|
-
magnus = "0.
|
|
19
|
+
magnus = "0.9"
|
|
20
20
|
rayon = "1"
|
|
21
21
|
|
|
22
22
|
[dependencies.css-inline]
|
|
23
|
-
version = "0.
|
|
23
|
+
version = "0.22.1"
|
|
24
24
|
default-features = false
|
|
25
25
|
features = ["http", "file", "stylesheet-cache"]
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: css_inline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dygalo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|