utilime

Small tools that finish the job.

Minify a stylesheet, a script or a page

Paste a stylesheet, a script or a page. It comes back shortened, with the byte count before and after, and the same pair measured again through gzip.

Drop a file hereor click to choose · it stays on your device

How it works

Minification is three different operations wearing one name, and the difference between them is the difference between a rewrite you can apply without reading the code and one that can change what the code does. Sorting them out is the only way to decide how far to let a tool go.

Tier one: removing bytes that were never data

Comments, indentation, the newline at the end of a statement. None of these survive parsing, so deleting them cannot alter the parse tree, and no correct program depends on them. This tier is unconditional and it holds most of the raw saving, because source code is mostly indentation. The exception is the comment a licence requires you to keep, which is what the licence toggle preserves: a comment opening with an exclamation mark, or carrying an @license or @preserve annotation, is the convention csso and terser both recognise.

Tier two: local rewrites that need a parser

Shortening #ffffff to #fff, dropping the semicolon before a closing brace, renaming a local variable from itemCount to n. Each is safe in isolation and wrong if the tool has misread what it is looking at. Renaming is the sharp one. A name can only change if every reference to it is visible, so a mangler renames function-scoped bindings and leaves top-level names, property names and anything reached through a string alone. The count of renamed identifiers reported below is therefore usually far lower than the number of variables in the file.

Tier three: structural change, which is what safe turns off

Merging two rules that share a declaration, reordering declarations, deleting a branch the compressor believes is unreachable. These change the shape of the program, and the shape is sometimes load-bearing. Two CSS rules of equal specificity are resolved by document order, so moving one past the other can move a colour. A compressor that drops a branch is right about the code and wrong about the debugger you were about to attach.

Safe performs tiers one and two and stops; full lets csso restructure and lets terser compress and mangle. The difference is measurable on the stylesheet in the sample above: safe leaves margin:0 0 0 0 and two separate rules, full writes margin:0 and merges the two selectors onto a single declaration.

Why newline removal in JavaScript is a parse, not a search

JavaScript ends statements at a line break under a set of rules called automatic semicolon insertion, so a return followed by a newline returns undefined and the expression below it is dead code. A tool that strips newlines textually turns that into a return of the expression, which is a different program that still runs. Terser parses first and prints a semicolon where the grammar implies one, so the meaning survives the reformatting.

The second trap in the same family: a forward slash opens a regular expression or performs a division depending only on the token before it, so /\s+/g and a/b/c are the same characters in different grammatical positions. Neither hazard can be settled by looking at the text.

Why HTML is minified least of the three

In an inline formatting context a run of whitespace collapses to a single space, and that space is rendered. Delete it between a closing anchor and an opening em and two words run together on the page. The HTML pass here collapses runs to one space and deletes a space only where it touches a block-level boundary or the edge of the document, the one position it could not have been drawn in.

Contents of pre and textarea are copied out unchanged, as is any element whose style attribute sets white-space to pre, pre-wrap, pre-line or break-spaces. Embedded style and script bodies go through csso and terser. A script typed as application/json or as a template MIME is left alone, because its body is not JavaScript.

The saving that reaches the wire

Almost every minifier reports the drop in raw bytes, and almost nothing is served as raw bytes. The transfer is gzipped or brotli-compressed, and DEFLATE already replaces a repeated run of spaces or a repeated long identifier with a short back-reference, so minification is deleting bytes the compressor was charging almost nothing for.

Both figures are measured here rather than assumed, on the same input, through CompressionStream. Measured on the sample this page opens with: 902 bytes become 543, a drop of 39.8%, while gzipped they go from 514 to 392, a drop of 23.7%. The saving is real, and it is about three-fifths of the one the uncompressed figure advertises.

Questions

Which minifiers is this actually running?

csso 5.0.5 for CSS and terser 5.49.2 for JavaScript, both compiled to run in the tab rather than on a server. HTML is handled by a pass written for this page, which collapses whitespace, removes comments and hands any embedded style or script body to those same two libraries. The library for the language you chose is fetched only when you choose it, so a CSS visitor never downloads the JavaScript parser.

What does the safe level actually stop?

For CSS it turns off csso's restructuring: no merging of rules that share declarations, no reordering, no collapsing of longhand into shorthand. For JavaScript it turns off both compress and mangle, so terser reprints the parse tree with the whitespace and comments gone and every name intact. For HTML it keeps a single space wherever whitespace occurred, even at a block boundary where it could not have been rendered.

Why is the gzipped saving so much smaller than the raw one?

Because the two operations remove the same redundancy. Indentation is a repeated string, and DEFLATE encodes a repeated string as a reference to its earlier occurrence, costing a few bits rather than a byte per character. Minification deletes those characters outright, which looks dramatic before compression and much less so afterwards. The gzipped pair is the one to quote in a performance budget.

Is it safe to mangle a script that is embedded in a page?

Top-level names survive mangling by default in terser, so a function called from an onclick attribute keeps its name. Anything declared inside a function is renamed, and a reference constructed as a string, such as a lookup through window by name, will not be found and updated. If a script is reached from markup by name, keep it at the safe level.

My JavaScript will not parse. What is reported?

The message terser produced, with the line and column it stopped at, in place of the output. Nothing is thrown, so the page never shows a stale answer beside a fresh error. A syntax error inside an embedded script in an HTML document is reported the same way, and that script body is copied out unchanged while the rest of the document is still minified.