# RefreshCSS π«§
[![All Contributors](https://img.shields.io/github/all-contributors/adamghill/refreshcss?color=ee8449&style=flat-square)](#contributors)
`RefreshCSS` is a Python library that removes unused classes, ids, and element selectors from CSS.
> Make your CSS so fresh, so clean.
## π§ Installation
### To use the `refreshcss` library or use the `django-compressor` integration
`pip install refreshcss`
### To run `refreshcss` on the command-line
`pip install refreshcss[cli]`
## βοΈ Features
- Pure Python (no extra NodeJS build process needed)
- Filters out unused classes, ids, elements from CSS based on HTML templates
- Handles Django/Jinja styles HTML templates
- Can be used as a filter with `django-compressor` to minify CSS as part of the `compress` management command
- Can be used via command-line interface in CI/CD
### β¨οΈ Command-line interface
> Make sure that the `cli` extra is installed first: `pip install refreshcss[cli]`.
```sh
Usage: refreshcss [OPTIONS] CSS HTML...
Remove classes, ids, and element selectors not used in HTML from CSS.
Options:
-o, --output FILENAME Write to file instead of stdout.
-R, -r, --recursive Recursively search subdirectories listed.
--encoding TEXT Character encoding to use when reading files. If not
specified, the encoding will be guessed.
--version Show the version and exit.
--help Show this message and exit.
```
### ποΈ Integrate with django-compressor
Add `"refreshcss.filters.RefreshCSSFilter"` to `COMPRESS_FILTERS` in the Django settings file.
```python
COMPRESS_FILTERS = {
"css": [
"refreshcss.filters.RefreshCSSFilter",
...
],
"js": [...],
}
```
### βοΈ Library
```python
from refreshcss import RefreshCSS, PathSite
def clean_css(css_path: Path):
# Parse the HTML files
site = PathSite(paths=["templates"], recursive=True)
site.parse()
# Get clean CSS based on the parsed HTML
css_text = css_path.read_text()
cleaned_css = RefreshCSS(site).clean(css_text)
return cleaned_css
```
## π€ How does it work?
1. Catalogue classes, ids, and elements that are currently being used in found HTML templates
1. Catalogue classes, ids, elements, and at-rules in a particular CSS stylesheet
1. Return new CSS stylesheet that only contains rules that are actively being used by the HTML
## π§ Why?
I wanted to have a filter for `django-compressor` that would purge unused CSS as part of the `compress` step when deploying for [`coltrane`](https://coltrane.readthedocs.io) apps. After dealing with a manual process and attempting to integrate https://purgecss.com and https://github.com/uncss/uncss I thought "this couldn't be that hard to do in Python".
Which is always the thought at the beginning of every side project... π
## π FAQ
### Will this work with SPAs?
Probably not. `RefreshCSS` only inspects HTML templates, so if CSS classes are being changed client-side then `refreshcss` will not know about it.
### Does this work by crawling a website URL?
Currently no, although that is a possibility in the future. PRs appreciated. π
### Does this support HTML written in the Django Template Language?
Yes! That was a primary reason I built my own solution. π
Jinja might also be possible to support with some small tweaks, although it is currently untested.
### Is this what people mean when they say "treeshaking"?
Maybe. π€·
### I found a bug!
Thanks for trying `RefreshCSS` out! Please make a PR (pull request) with a small test that replicates the bug or, if that is not possible, create a [new discussion](https://github.com/adamghill/refreshcss/discussions/new?category=ideas).
## π€ Related libraries
### Node
- [uncss](https://github.com/uncss/uncss)
- [PurgeCSS](https://purgecss.com/)
### Python
- [treeshake](https://pypi.org/project/treeshake/): I unfortunately could not get this to work on my local environment.
- [cssutils](https://pypi.org/project/cssutils/): This unfortunately seemed to choke on more modern CSS when I tested on Bulma 1.0.
- [css-optomizer](https://github.com/hamzaehsan97/CSS-optomizer)
## π Thanks
- [Django](https://www.djangoproject.com)
- [django-compressor](https://django-compressor.readthedocs.io/)
- [CSS standards](https://www.w3.org/Style/CSS/)
## β€οΈ Support
This project is supported by GitHub [Sponsors](https://github.com/sponsors/adamghill) and [Digital Ocean](https://m.do.co/c/617d629f56c0).
<p>
<a href="https://m.do.co/c/617d629f56c0">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
</a>
</p>
## π₯³ Contributors
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://git.boelz.eu/tmb/"><img src="https://avatars.githubusercontent.com/u/641522?v=4?s=100" width="100px;" alt="Tobias BΓΆlz"/><br /><sub><b>Tobias BΓΆlz</b></sub></a><br /><a href="#code-tobiasmboelz" title="Code">π»</a> <a href="#doc-tobiasmboelz" title="Documentation">π</a> <a href="#test-tobiasmboelz" title="Tests">β οΈ</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
Raw data
{
"_id": null,
"home_page": "https://github.com/adamghill/refreshcss/",
"name": "refreshcss",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.10",
"maintainer_email": null,
"keywords": "django, python, css, html",
"author": "adamghill",
"author_email": "adamghill@yahoo.com",
"download_url": "https://files.pythonhosted.org/packages/b0/41/c3b701cce178cc01121351df5975faa29b37e6818127764b4990b21f504b/refreshcss-0.5.1.tar.gz",
"platform": null,
"description": "# RefreshCSS \ud83e\udee7\n\n[![All Contributors](https://img.shields.io/github/all-contributors/adamghill/refreshcss?color=ee8449&style=flat-square)](#contributors)\n\n`RefreshCSS` is a Python library that removes unused classes, ids, and element selectors from CSS.\n\n> Make your CSS so fresh, so clean.\n\n## \ud83d\udd27 Installation\n\n### To use the `refreshcss` library or use the `django-compressor` integration\n\n`pip install refreshcss`\n\n### To run `refreshcss` on the command-line\n\n`pip install refreshcss[cli]`\n\n## \u2b50\ufe0f Features\n\n- Pure Python (no extra NodeJS build process needed)\n- Filters out unused classes, ids, elements from CSS based on HTML templates\n- Handles Django/Jinja styles HTML templates\n- Can be used as a filter with `django-compressor` to minify CSS as part of the `compress` management command\n- Can be used via command-line interface in CI/CD\n\n### \u2328\ufe0f Command-line interface\n\n> Make sure that the `cli` extra is installed first: `pip install refreshcss[cli]`.\n\n```sh\nUsage: refreshcss [OPTIONS] CSS HTML...\n\n Remove classes, ids, and element selectors not used in HTML from CSS.\n\nOptions:\n -o, --output FILENAME Write to file instead of stdout.\n -R, -r, --recursive Recursively search subdirectories listed.\n --encoding TEXT Character encoding to use when reading files. If not\n specified, the encoding will be guessed.\n --version Show the version and exit.\n --help Show this message and exit.\n```\n\n### \ud83d\udddc\ufe0f Integrate with django-compressor\n\nAdd `\"refreshcss.filters.RefreshCSSFilter\"` to `COMPRESS_FILTERS` in the Django settings file.\n\n```python\nCOMPRESS_FILTERS = {\n \"css\": [\n \"refreshcss.filters.RefreshCSSFilter\",\n ...\n ],\n \"js\": [...],\n}\n```\n\n### \u2699\ufe0f Library\n\n```python\nfrom refreshcss import RefreshCSS, PathSite\n\ndef clean_css(css_path: Path):\n # Parse the HTML files\n site = PathSite(paths=[\"templates\"], recursive=True)\n site.parse()\n\n # Get clean CSS based on the parsed HTML\n css_text = css_path.read_text()\n cleaned_css = RefreshCSS(site).clean(css_text)\n\n return cleaned_css\n```\n\n## \ud83e\udd13 How does it work?\n\n1. Catalogue classes, ids, and elements that are currently being used in found HTML templates\n1. Catalogue classes, ids, elements, and at-rules in a particular CSS stylesheet\n1. Return new CSS stylesheet that only contains rules that are actively being used by the HTML\n\n## \ud83e\uddd0 Why?\n\nI wanted to have a filter for `django-compressor` that would purge unused CSS as part of the `compress` step when deploying for [`coltrane`](https://coltrane.readthedocs.io) apps. After dealing with a manual process and attempting to integrate https://purgecss.com and https://github.com/uncss/uncss I thought \"this couldn't be that hard to do in Python\".\n\nWhich is always the thought at the beginning of every side project... \ud83d\ude05\n\n## \ud83d\ude4b FAQ\n\n### Will this work with SPAs?\n\nProbably not. `RefreshCSS` only inspects HTML templates, so if CSS classes are being changed client-side then `refreshcss` will not know about it.\n\n### Does this work by crawling a website URL?\n\nCurrently no, although that is a possibility in the future. PRs appreciated. \ud83d\ude09\n\n### Does this support HTML written in the Django Template Language?\n\nYes! That was a primary reason I built my own solution. \ud83d\ude05 Jinja might also be possible to support with some small tweaks, although it is currently untested.\n\n### Is this what people mean when they say \"treeshaking\"?\n\nMaybe. \ud83e\udd37\n\n### I found a bug!\n\nThanks for trying `RefreshCSS` out! Please make a PR (pull request) with a small test that replicates the bug or, if that is not possible, create a [new discussion](https://github.com/adamghill/refreshcss/discussions/new?category=ideas).\n\n## \ud83e\udd18 Related libraries\n\n### Node\n\n- [uncss](https://github.com/uncss/uncss)\n- [PurgeCSS](https://purgecss.com/)\n\n### Python\n\n- [treeshake](https://pypi.org/project/treeshake/): I unfortunately could not get this to work on my local environment.\n- [cssutils](https://pypi.org/project/cssutils/): This unfortunately seemed to choke on more modern CSS when I tested on Bulma 1.0.\n- [css-optomizer](https://github.com/hamzaehsan97/CSS-optomizer)\n\n## \ud83d\ude4f Thanks\n\n- [Django](https://www.djangoproject.com)\n- [django-compressor](https://django-compressor.readthedocs.io/)\n- [CSS standards](https://www.w3.org/Style/CSS/)\n\n## \u2764\ufe0f Support\n\nThis project is supported by GitHub [Sponsors](https://github.com/sponsors/adamghill) and [Digital Ocean](https://m.do.co/c/617d629f56c0).\n\n<p>\n <a href=\"https://m.do.co/c/617d629f56c0\">\n <img src=\"https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg\" width=\"201px\">\n </a>\n</p>\n\n## \ud83e\udd73 Contributors\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n <tbody>\n <tr>\n <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://git.boelz.eu/tmb/\"><img src=\"https://avatars.githubusercontent.com/u/641522?v=4?s=100\" width=\"100px;\" alt=\"Tobias B\u00f6lz\"/><br /><sub><b>Tobias B\u00f6lz</b></sub></a><br /><a href=\"#code-tobiasmboelz\" title=\"Code\">\ud83d\udcbb</a> <a href=\"#doc-tobiasmboelz\" title=\"Documentation\">\ud83d\udcd6</a> <a href=\"#test-tobiasmboelz\" title=\"Tests\">\u26a0\ufe0f</a></td>\n </tr>\n </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Removes unused classes, ids, and element selectors from CSS.",
"version": "0.5.1",
"project_urls": {
"Documentation": "https://github.com/adamghill/refreshcss/",
"Funding": "https://github.com/sponsors/adamghill",
"Homepage": "https://github.com/adamghill/refreshcss/",
"Repository": "https://github.com/adamghill/refreshcss/"
},
"split_keywords": [
"django",
" python",
" css",
" html"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "56a432a5177f5d69362b7060d1b3a5e6cba1338503cca4b95f42c566a0c96030",
"md5": "47d354173cf56a0eca7fc5db5228ba21",
"sha256": "6048c156ab2f1cbd429eb273e158ebae41f32a5696eab7ee19efe6d9ce1c3de0"
},
"downloads": -1,
"filename": "refreshcss-0.5.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "47d354173cf56a0eca7fc5db5228ba21",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.10",
"size": 14389,
"upload_time": "2024-09-01T01:42:54",
"upload_time_iso_8601": "2024-09-01T01:42:54.657227Z",
"url": "https://files.pythonhosted.org/packages/56/a4/32a5177f5d69362b7060d1b3a5e6cba1338503cca4b95f42c566a0c96030/refreshcss-0.5.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "b041c3b701cce178cc01121351df5975faa29b37e6818127764b4990b21f504b",
"md5": "80aa9c0a4a509a27b751503758cf9d4d",
"sha256": "b81b2ce6b675f238ca89b0e946d5e0366a55f41535b5ae3d7691961d5e002b88"
},
"downloads": -1,
"filename": "refreshcss-0.5.1.tar.gz",
"has_sig": false,
"md5_digest": "80aa9c0a4a509a27b751503758cf9d4d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.10",
"size": 13895,
"upload_time": "2024-09-01T01:42:55",
"upload_time_iso_8601": "2024-09-01T01:42:55.646501Z",
"url": "https://files.pythonhosted.org/packages/b0/41/c3b701cce178cc01121351df5975faa29b37e6818127764b4990b21f504b/refreshcss-0.5.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-01 01:42:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "adamghill",
"github_project": "refreshcss",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "refreshcss"
}