CSS filters and formatters in golang
Use awesome CSS frameworks without the weight by cutting out unused rules.
csscut is similar to purgecss (GitHub). It scans your HTML for elements, classes and identifiers and then cuts out any CSS rule that doesn't apply. The results for a small site using a framework like bootstrap can be dramatic:
| Bootstrap | csscut | savings | |
|---|---|---|---|
| uncompressed | 141k | 8.1k | 94% |
| compressed | 20k | 2.6k | 87% |
See also Hugo #4446
For use with hugo using bootstrap:
# install the binary
go get github.com/client9/csstool/css
# build your site, by default the output is in `public`
hugo
# create new minimized CSS file from bootstrap
curl -s https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css | \
css cut --html 'public/**/*.html' > static/bootstrap-csscut.min.cssOf course, you'll need to use the new bootstrap-csscut.min.css file in your template source.
Be sure to put the HTML file pattern 'public/**/*.html' in single quotes.
TK - likely to change, feedback welcome
TK - likely to change, feedback welcome
The "correct way" to strip out CSS rules might be:
- Read in all the CSS files, and extract all the selectors
- For each HTML file, execute each selector and see if it returns anything
- Use that data to the emit each CSS file with only the selectors that were used.
There are a few problems:
- Slow, as you are executing n CSS rules against m HTML files.
- Need a perfect CSS Level 3 (or 4!) selector library, else you might strip out rules that are actually used.
- Need to know which pseudo-classes matter and which ones do not. For instance
:hovercan be ignored, but:last_childneeds to be evaluated.
Since the Correct Way seems problematic, csscut does the following:
- Read each HTML file and keep track of elements, classes and ids found.
- Scan the CSS file and using the primary selector and previous step, keep or remove the selector and it's rule. Combinators and pseudo-elements are ignored in making the decision.
If the li element is found in the html then the CSS selector is also allowed li:first-of-type and li li even if you don't have a nested list. If img is found, then the CSS rule img ~ p is also allowed, even if you don't have paragraph as a sibling of an image.
As a special case, "universal selectors" are passed through: *, ::before, ::after, ::root. Pure attribute selectors are also passed through: [hidden].
In practice this works well for "flat" CSS frameworks such as bootstrap. For highly specified CSS it might not work as well.
Makes minified CSS readable.
css format < bootstrap.min.css
css minify < bootstrap.min.css
minify is a short cut of 'css format' with all options selected to produce the smallest output.
See commonly or rarely used CSS classes and identifiers.
Work in progress
- The CSS parsing is done by the most excellent tdewolff/parse which powers tdewolff/minify.
- The double star globbing / pattern matching is handled by mattn/go-zglob