Skip to main content

css_inline

build status pypi versions license codecov.io gitter

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
  • 10-500x faster than alternatives
  • Inlines CSS from style and link tags
  • Removes style and link tags
  • Resolves external stylesheets (including local files)
  • Optionally caches external stylesheets
  • Can process multiple documents in parallel
  • Works on Linux, Windows, macOS and in the browser via PyOdide
  • Supports HTML5 & CSS3
  • Tested on CPython 3.10, 3.11, 3.12, 3.13, 3.14 and PyPy 3.11.

Playground

If you'd like to try css-inline, you can check the WebAssembly-powered playground to see the results instantly.

Installation

Install with pip:

pip install css_inline

Pre-compiled wheels are available for most popular platforms. If not available for your platform, a Rust compiler will be needed to build this package from source. Rust version 1.65 or higher is required.

Usage

import css_inline

HTML = """<html>
<head>
    <style>h1 { color:blue; }</style>
</head>
<body>
    <h1>Big Text</h1>
</body>
</html>"""

inlined = css_inline.inline(HTML)
# HTML becomes this:
#
# <html>
# <head>
#    <style>h1 { color:blue; }</style>
# </head>
# <body>
#     <h1 style="color:blue;">Big Text</h1>
# </body>
# </html>

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 inline if you need to keep the full document structure:

FRAGMENT = """<main>
<h1>Hello</h1>
<section>
<p>who am i</p>
</section>
</main>"""

CSS = """
p {
    color: red;
}

h1 {
    color: blue;
}
"""

inlined = css_inline.inline_fragment(FRAGMENT, CSS)
# HTML becomes this:
# <main>
# <h1 style="color: blue;">Hello</h1>
# <section>
# <p style="color: red;">who am i</p>
# </section>
# </main>

When there is a need to inline multiple HTML documents simultaneously, css_inline offers inline_many and inline_many_fragments functions. This feature allows for concurrent processing of several inputs, significantly improving performance when dealing with a large number of documents.

import css_inline

css_inline.inline_many(["<...>", "<...>"])

Under the hood, inline_many, spawns threads at the Rust layer to handle the parallel processing of inputs. This results in faster execution times compared to employing parallel processing techniques at the Python level.

Note: To fully benefit from inline_many, you should run your application on a multicore machine.

Configuration

For configuration options use the CSSInliner class:

import css_inline

inliner = css_inline.CSSInliner(keep_style_tags=True)
inliner.inline("...")
  • 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
  • keep_at_rules. Specifies whether to keep "at-rules" (starting with @) after inlining. Default: False
  • minify_css. Specifies whether to remove trailing semicolons and spaces between properties and values. 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 caching options for external stylesheets (for example, StylesheetCache(size=5)). 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
  • remove_inlined_selectors. Specifies whether to remove selectors that were successfully inlined from <style> blocks. Default: False
  • apply_width_attributes. Specifies whether to add width HTML attributes from CSS width properties on supported elements (table, td, th, img). Default: False
  • apply_height_attributes. Specifies whether to add height HTML attributes from CSS height properties 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:

<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>

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>

If you'd like to load stylesheets from your filesystem, use the file:// scheme:

import css_inline

# styles/email is relative to the current directory
inliner = css_inline.CSSInliner(base_url="file://styles/email/")
inliner.inline("...")

You can also cache external stylesheets to avoid excessive network requests:

import css_inline

inliner = css_inline.CSSInliner(
    cache=css_inline.StylesheetCache(size=5)
)
inliner.inline("...")

Caching is disabled by default.

XHTML compatibility

If you'd like to work around some XHTML compatibility issues like closing empty tags (<hr> vs. <hr/>), you can use the following snippet that involves lxml:

import css_inline
from lxml import html, etree

document = "..."  # Your HTML document
inlined = css_inline.inline(document)
tree = html.fromstring(inlined)
inlined = etree.tostring(tree).decode(encoding="utf-8")

Performance

css-inline is powered by efficient tooling from Mozilla's Servo project and significantly outperforms other Python alternatives in terms of speed. Most of the time it achieves over a 10x speed advantage compared to the next fastest alternative.

Here is the performance comparison:

Size css_inline 0.19.0 premailer 3.10.0 toronado 0.1.0 inlinestyler 0.2.5 pynliner 0.8.0
Basic 230 B 4.27 µs 85.05 µs (19.93x) 495.30 µs (116.05x) 1.02 ms (238.87x) 867.79 µs (203.32x)
Realistic-1 8.58 KB 80.59 µs 1.03 ms (12.76x) 11.55 ms (143.29x) 26.37 ms (327.21x) 11.71 ms (145.36x)
Realistic-2 4.3 KB 46.88 µs 1.44 ms (30.73x) ERROR 17.71 ms (377.77x) ERROR
GitHub page 1.81 MB 17.57 ms 10.78 s (613.48x) ERROR ERROR ERROR

The "Basic" case was obtained by benchmarking the example from the Usage section. Note that the toronado, inlinestyler, and pynliner libraries encountered errors when used to inline CSS in the last scenarios.

The benchmarking code is available in the benches/bench.py file. The benchmarks were conducted using the stable rustc 1.91, Python 3.14.2 on Ryzen 9 9950X.

Comparison with other libraries

Besides performance, css-inline differs from other Python libraries for CSS inlining.

  • Generally supports more CSS features than other libraries (for example, toronado and pynliner do not support pseudo-elements);
  • It has fewer configuration options and is not as flexible as premailer;
  • Works on fewer platforms than LXML-based libraries (premailer, inlinestyler, toronado, and optionally pynliner);
  • Does not have debug logs yet;
  • Supports only HTML 5.

Further reading

If you want to know how this library was created & how it works internally, you could take a look at these articles:

License

This project is licensed under the terms of the MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

css_inline-0.21.2.tar.gz (73.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_x86_64.whl (2.0 MB view details)

Uploaded PyPymanylinux: glibc 2.24+ x86-64

css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_aarch64.whl (1.9 MB view details)

Uploaded PyPymanylinux: glibc 2.24+ ARM64

css_inline-0.21.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded PyPymacOS 10.12+ x86-64

css_inline-0.21.2-cp310-abi3-win_amd64.whl (1.9 MB view details)

Uploaded CPython 3.10+Windows x86-64

css_inline-0.21.2-cp310-abi3-win32.whl (1.6 MB view details)

Uploaded CPython 3.10+Windows x86

css_inline-0.21.2-cp310-abi3-pyemscripten_2025_0_wasm32.whl (529.0 kB view details)

Uploaded CPython 3.10+PyEmscripten 2025.0 wasm32

css_inline-0.21.2-cp310-abi3-musllinux_1_2_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ x86-64

css_inline-0.21.2-cp310-abi3-musllinux_1_2_armv7l.whl (2.0 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARMv7l

css_inline-0.21.2-cp310-abi3-musllinux_1_2_aarch64.whl (2.1 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

css_inline-0.21.2-cp310-abi3-manylinux_2_24_armv7l.whl (1.8 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.24+ ARMv7l

css_inline-0.21.2-cp310-abi3-manylinux_2_24_aarch64.whl (1.9 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.24+ ARM64

css_inline-0.21.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

css_inline-0.21.2-cp310-abi3-manylinux_2_12_i686.manylinux2010_i686.whl (1.9 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.12+ i686

css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (3.6 MB view details)

Uploaded CPython 3.10+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file css_inline-0.21.2.tar.gz.

File metadata

  • Download URL: css_inline-0.21.2.tar.gz
  • Upload date:
  • Size: 73.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.12

File hashes

Hashes for css_inline-0.21.2.tar.gz
Algorithm Hash digest
SHA256 13123c184189646041cc02a792a6b9ea346955d166f74d7b2837621ba17e22f3
MD5 5aa098e23b6932007e6f501d3d7aca87
BLAKE2b-256 9acc8c2ab532dc10d0aea05b0a8e86a01df7b1fff7f187acb6acf6aa422d60f9

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 76129486691f792779a71f9dc8ba26d0c70f3100a2f46374bc548297b7712dc8
MD5 a974f69b64ff69ca5e73d7edb017338f
BLAKE2b-256 c72e7d88d306e800d39b238f7f50b942d1e52ff78cb38fd169f86906922feef1

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_aarch64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-pp311-pypy311_pp73-manylinux_2_24_aarch64.whl
Algorithm Hash digest
SHA256 03c84690078f03203ccb322810a099be491b054b5f64dc71b8c8c68fff7942d8
MD5 4b68472c9cdaab2cd04e2bd33e6934ac
BLAKE2b-256 ed877b954ffe60f5a67fde7fa41a48f0c76f717de8cc7ac241207251c2572f71

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 95d1e4b1421ad03a032daabe1e0af76c5168cab423d1f1a121bdf512f87bc34a
MD5 e3d85d63b468b28c8af113fa9c4dba75
BLAKE2b-256 1f5f7510446e42182c87fe16634179459e35187cb92f780f356f3126cd9ef244

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: css_inline-0.21.2-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.12

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7a9abdcac2597dc4381dc5436f4c581132b9ec30b4d2408ed397927e6211f7a9
MD5 3a377988f3d5606adf483cf660225c03
BLAKE2b-256 cb350efcac410f4a65a259650350dec2de42ae04fdb4a40ac23c87618782ee61

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-win32.whl.

File metadata

  • Download URL: css_inline-0.21.2-cp310-abi3-win32.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.10+, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.12

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-win32.whl
Algorithm Hash digest
SHA256 82609509b70f6ba62350ffce9f2ddb2fea6a443ca19bf5ae338246be09d8792e
MD5 e36bef4f05e14a9d3b79fc98745b31fc
BLAKE2b-256 3921315da2226e01d7571d83e0fe28296aab5f094689d0f9efaa215259eee7fb

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-pyemscripten_2025_0_wasm32.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-pyemscripten_2025_0_wasm32.whl
Algorithm Hash digest
SHA256 15657248f4167c23ff553c33989f1d2a1855141643db56bb5accab9392342006
MD5 36349a12c6c70210f0bc17eac9760e4a
BLAKE2b-256 5de09a901b564055d4395ccc434b43840627a206e770afcea6bbf479fc3dbfb7

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 59a999aa4a30bd1541f0f0926a3f9304723b42e46ce8e336d99d167a6ce8defc
MD5 add83e08c46a33792b06dccfb135081c
BLAKE2b-256 2d5f618da923d3cb8cbf7a175af3cfa86f20748e0d41e8df780c0d16d697b947

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 e89aa59e862972b5435f8573cefb99c64d7291bcd82a5bd2840097b14216a862
MD5 2eca0e9b657cbbf2f792888981d88720
BLAKE2b-256 419a2d5c6a605e4671bd6a847e2ad22c67011290528b55632bea2b93c03f505c

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 db5f5a450f6c0290a3c502db18289685cc8bc5c06187dd4bd59f10959af86e9d
MD5 64165220f6133eddad41e2746a5bd751
BLAKE2b-256 ce98cfe16f86d71ae66b52df931d0c91ec7101c712c121485a33a1b9ef6f5a29

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-manylinux_2_24_armv7l.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-manylinux_2_24_armv7l.whl
Algorithm Hash digest
SHA256 66db8c999665a36b75b37958815ea4a288d0fc2d536a9aecdc4266a462097e9e
MD5 3258cbceca79ad97a3753e91dc36e30e
BLAKE2b-256 8f52c4c397644a3b701e550288546d199fc777eb46c3f485ce7a989788dbc2db

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-manylinux_2_24_aarch64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-manylinux_2_24_aarch64.whl
Algorithm Hash digest
SHA256 6cc63fe809aaa9eeba6c5effaf3cd04a7173f70b34bd128283e0cbc3b2e99488
MD5 0a2903125667776bcb646ac5d9557b8f
BLAKE2b-256 734ae0fd2e75c656415132a8960b90971edc81e20f57268583c80cb1ebcbba25

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c7dd8b0fe8137b4d058e1e8d390d61a94f7051490b5560aaca881cb0436f732
MD5 2fa46c1b610e86312ae695f84aa8013a
BLAKE2b-256 b4f877488b9314c62ad62ec8d83b71402dca5ff36cd9cf55e518a83069c13bfc

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-manylinux_2_12_i686.manylinux2010_i686.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 caecd929263c7f339123bf6c1296eb19790ecf86587d7571d177b2ab86f7c9c0
MD5 29fded20ce93bf06b0983cba07eaeb0c
BLAKE2b-256 9b63b581c765dcc7ddefc23de6ca4fdc6a320b81376cfae5b8925e777b46c057

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8241f85a7cb70dfbc62b2926b6ea7d1d2f8fe2c759cf0fbd1f1483cb05c95e25
MD5 2fbddc005742dc791a5f5da69acb48c9
BLAKE2b-256 16835a82168fc1e9daa8556cac774e5a350f16597462023ae7464c20d30f8a1d

See more details on using hashes here.

File details

Details for the file css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for css_inline-0.21.2-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 1f9deda7442743499bd4273ca1bfa2583ae78257c5e3461a54f2fbd3a7493052
MD5 4c3ab485e14d82e3e2e6dd6b699bcea4
BLAKE2b-256 728358f8c2fd91459303f10c2cc652eed8ff73ff3830f339829512e8dcf797ac

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.21.2 This release

16 files

0.21.1

16 files

0.21.0

16 files

0.20.2

15 files

0.20.1

15 files

0.20.0

15 files

0.19.1

15 files

0.19.0

15 files

0.18.0

15 files

0.17.0

18 files

0.16.0

18 files

0.15.0

18 files

0.14.6

24 files

0.14.5

9 files

0.14.3

24 files

0.14.2

24 files

0.14.1

24 files

0.14.0

24 files

0.13.0

24 files

0.12.0

24 files

0.11.2

24 files

0.11.1

24 files

0.11.0

21 files

0.10.5

21 files

0.10.4

21 files

0.10.3

21 files

0.10.2

21 files

0.10.1

21 files

0.10.0

21 files

0.9.0

21 files

0.8.7

21 files

0.8.6

21 files

0.8.5

21 files

0.8.4

40 files

0.8.3

52 files

0.8.2

48 files

0.8.1

48 files

0.8.0

47 files

0.7.8

16 files

0.7.7

16 files

0.7.6

13 files

0.7.5

13 files

0.7.4

13 files

0.7.3

13 files

0.7.2

13 files

0.7.1

13 files

0.7.0

13 files

0.6.2

16 files

0.6.1

16 files

0.6.0

14 files

0.5.0

13 files

0.4.0

13 files

0.3.2

13 files

0.3.1

13 files

0.3.0

13 files

0.2.0

13 files

0.1.0

13 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page