
What CSS minifiers also leave behind - remy_luisant
https://luisant.ca/css-opts-survey2
======
josephg
The scientific notation one is a bug. Scientific notation isn't part of the
CSS spec[1], and its not supported in all browsers.

I learned this one the hard way a few months ago. We ran into a flexbox bug in
one browser which we worked around by adding some-rule: 0.0000001px instead of
0px. However, our minifier collapsed that using scientific notation, which
triggered a rendering issue in a _different_ browser due to the out-of-spec
CSS. The whole adventure left me feeling like I'd travelled back in time.

[1]
[https://www.w3.org/TR/CSS21/syndata.html#numbers](https://www.w3.org/TR/CSS21/syndata.html#numbers)

~~~
legulere
Scientific notation seems to be part of CCS3:

[https://www.w3.org/TR/css3-values/#numbers](https://www.w3.org/TR/css3-values/#numbers)

Which browser had problems with it?

~~~
masklinn
"q" is also CSS3, incidentally, and its background is interesting[0]: it's a
mostly japanese metric typographical unit[1], it replaces the point, and is
slightly smaller: q is 0.25mm while pt is ~0.3528mm (precisely 1/72th of an
inch which is 25.4mm).

[0] [http://tosche.net/2013/10/font-size-in-the-metric-
system_e.h...](http://tosche.net/2013/10/font-size-in-the-metric-
system_e.html)

[1] although non-japanese typographers like Otl Aicher have recommended its
use it doesn't seem to have had much success outside Japan

~~~
kijin
"q" seems to be doomed to failure. If I were that interested in moving away
from points and ems, why would I adopt arbitrary fractions of a millimeter
when I could just use plain old SI units that are universally understood? It
doesn't even save a byte at typical font sizes: 20q == 5mm.

~~~
ygra
Saving bytes in CSS was probably not the primary concern upon standardization
in 1976. Note that the PostScript point (now the most common definition) is
younger than that. Common usage doesn't always follow the best option that's
available, as evident by many examples throughout history.

Furthermore, having a measurement that can frequently be used with integer
dimensions is _convenient_ , which is probably a large part why we still use
points. 12 pt is a convenient font size, so is 4 mm (technically 4.2 mm, as
11.8 pt would be 4 mm), but while 10 pt is still convenient, 3.5 mm is less
so. Smaller units lead to more useful integer values (within reason, of
course).

------
remy_luisant
Author here.

Wow. #1 on HN. Wow.

I'd usually hang around a bit more, but I'm really tired. I posted this past
my midnight. 00:51 now, and I'm fading fast.

Thanks for all the love, everyone. I'll come over tomorrow (12 hours from now,
or so) to answer any questions or to pick up any corrections.

~~~
catenthusiast
I hope you sleep well.

~~~
remy_luisant
:3

------
cornedor
> I'm guessing that at nine nines that is pretty much a one anyway and it
> would not even change a single pixel on the screen.

There used to be a bug with flex-wrap: wrap; where an element would wrap to
the next line while it should have fit. You could fix it by instead using
width: 25%; use width: 24.999999%; so it would be 25% on the screen but it
would fix the problem so it didn't wrap to the next line. So you should look
out with this.

~~~
b34r
That sounds like the time-honored single whitespace bug. Usually fix it with
margin-left: -4px on all but the first element in the row.

------
pasta
This looks like a fun project indeed!

Unfortunately every time I read something about minifiers I got the feeling
that people are optimizing the wrong problem.

If you gzip data over the line it's already compressed. So minifying your
stuff will only help you a little.

The problem is on the client side. You can compress what you like but if the
browser starts dropping frames because it has to compile/handle a ton of
Javascript and CSS then minifying doesn't help the end user.

~~~
dspillett
_> If you gzip data over the line it's already compressed. So minifying your
stuff will only help you a little._

For small files you might be mostly correct, but for larger ones min+compress
can product much better gains than compression alone.

IIRC the algorithm used employs a rolling compression window, and can only
match strings of tokens whose distance apart is smaller than that window. IIRC
the default window is 8KBytes and the maximum is 32KBytes. Even if you use the
maximum at the expense of CPU time that isn't going to cover many large files.
Minifying increases the effective range of the compression window, each match
is shorter but you will find more matches and usually this balances out in a
way that benefits the compression result.

It isn't quite that simple in reality as there is huffman encoding and other
tricks in the mix. This means that even for inputs smaller than the
compression window you may see some benefit as minifying can reduce the input
data's alphabet significantly.

Ignoring the "why it helps", it is easy to show that it _does_ help in a great
many real cases:

    
    
      ds@s2:/tmp$ wget --quiet https://code.jquery.com/jquery-3.2.0.min.js
      ds@s2:/tmp$ wget --quiet https://code.jquery.com/jquery-3.2.0.js
      ds@s2:/tmp$ gzip jquery-3.2.0.min.js
      ds@s2:/tmp$ gzip jquery-3.2.0.js
      ds@s2:/tmp$ ls -l j*
      -rw-r--r-- 1 ds ds 79201 Mar 16 21:30 jquery-3.2.0.js.gz
      -rw-r--r-- 1 ds ds 30023 Mar 16 21:30 jquery-3.2.0.min.js.gz

In this example the result of min+comp is less than 40% the size of the result
from compression alone.

For completeness, minifying alone achieves less than compression alone:

    
    
      -rw-r--r-- 1 ds ds 267686 Mar 16 21:30 jquery-3.2.0.js
      -rw-r--r-- 1 ds ds  79201 Mar 16 21:30 jquery-3.2.0.js.gz
      -rw-r--r-- 1 ds ds  86596 Mar 16 21:30 jquery-3.2.0.min.js
      -rw-r--r-- 1 ds ds  30023 Mar 16 21:30 jquery-3.2.0.min.js.gz
    

One further factor is CPU time consumed on the client decompressing and
parsing the content but this is likely to be insignificant compared to the
network or local IO time, if a device's CPU is under-powered enough that this
_is_ significant then it is unlikely to be able to run the decompressed code
with useful performance.

~~~
ricardobeat
Most of the gains in there are from stripping out comments. That plus
whitespace removal gets you most of the benefit. I don't think the parent was
advocating for dropping minification completely, but investing massive effort
when you're already at the crest of the curve.

~~~
diamondo25
Stripping out comments would be one, but eventually remove _all_ useless code
and optimizing it using tools like Google Closure Compiler is way more
effective in most websites that use a single bundle for everything.

~~~
ricardobeat
When the subject is CSS, dead code removal is a way more complex problem, and
only possible if your usage falls within certain constraints. Best bet is a
component system with scopes styles that ensures you are only loading what is
required.

------
replete
Don't mean to squash any enthusiasm, but these types of 1byte optimization
savings don't really have real-world benefits due to over-the-wire compression
like gzip and Brotli.

A more interesting problem to solve, I think, is that of optimising CSS rules
for browser rendering.

~~~
phire
I think that there is merit in designing a minifier that is explicitly
designed to optimise the gziped size rather than the uncompressed size.

Things like:

* Rearrange rules within the file to put similar rules within the sliding window.

* Rearrange rules so that tail of the last declaration of one rule and the start of the next selector create the longest possible common substring.

* Rearrange the order of declarations within the rules to maximize the length of common substrings that span two declarations, ie ": 2em;\nbackground-color: rgb("

~~~
remy_luisant
I'm working on one, though I'm not sure if it will ever see the light of the
day. I have four months of free time and if someone would feed and house me
for that time, I'd do it and open source it.

Any sponsors? No? Didn't think so. Not even you, big G? Aww...

For now some minifiers do sort the values, which helps.

~~~
thaunatos
Maybe open-source it anyways? :-)

~~~
remy_luisant
I won't have it any other way.

The "not starving to death" thing is a bit of an issue on the way there...
Well, I have savings, but...

And if I get a horrid job, then I won't have the energy. :P

------
Silhouette
Here's the same author's earlier post on this subject, "The missed chances:
What minifiers leave behind", from last week:

[https://luisant.ca/css-opts-survey](https://luisant.ca/css-opts-survey)

~~~
cfqycwz
Anybody know if the transparency one is actually a desirable optimization?
Iirc, you might want to assign a color to your transparency so it's not
shifting hue as you fade it in through CSS transitions, animations, or JS.

~~~
bastawhiz
Author of crass here. That's interesting: if you have a specific case where
the browser doesn't do what you'd expect, I'd love to see it in a Github
issue!

[https://github.com/mattbasta/crass/issues/new](https://github.com/mattbasta/crass/issues/new)

~~~
cfqycwz
I was thinking of the fact that transparent is supposedly an alias for
rgba(0,0,0,0), but this doesn't seem to cause an issue when I try it out, in
Firefox at least.

------
ovao
crass is doing some really wonderful stuff here -- I'm impressed!

It's very interesting, however, that no one minifier is a consistent winner in
these test cases, and that running CSS through multiple minifiers is actually,
potentially, not all that crazy. (The very debatable _real_ value in doing
that notwithstanding.)

~~~
bastawhiz
I appreciate the compliment! (author of crass here)

I've mentioned it before, but it's really not a great idea to use multiple
minifiers. Minifier bugs can get nasty, and using multiple minifiers
exponentially increases the likelihood that you'll encounter some weird or
broken behavior. Make sure to test thoroughly.

~~~
remy_luisant
And I will mention it one more time: I totally agree with you. It needs to be
said.

------
mercer
I have a slightly-related question for those of you familiar with Webpack, css
modules (css-loader/style-loader), and perhaps React as well: is there any
reason not to use the 'default' approach where the styles for the components
are simply inserted in a <style> (with unique, generated classnames)?

To be clear: I don't mean philosophical reasons. I personally love letting
javascript deal with the 'cascading' part and I don't have a problem with the
idea of having styling embedded in the final page.

What I'm curious about is if this has any kind of negative impact on
performance, bandwidth, etc. Because the CSS is loaded on the component level,
and because Webpack 2 does tree shaking, the page will be guaranteed to only
contain CSS for the components that are on the page. And if I'd 'lazy-load'
parts of the app, I'd get that benefit for my CSS as well with no extra
effort.

On the other hand, any benefits of having a compiled (and hopefully cached)
bundle.css are offset by the need for an extra request for the css file, as
well as the very likely situation that there'll be a bunch of unused css in
that bundle.

Am I missing some drawback to the above-mentioned approach?

~~~
bastawhiz
When you're using a loader, the CSS still exists, it's just a big string in
your JS bundle. By default, I believe css-loader/style-loader will use cssnano
to minify the CSS within your bundle.

What will be very interesting in the coming years (as the work gets done
around it) is "full css" optimization. That is, when you know you have all of
the styles for the whole page available to the minifier. If the minifier knows
that no other CSS is being loaded, it can do a lot more work to remove and
merge rulesets. In the case of styles bundled with Webpack, common CSS could
be reduced even further, after tree shaking has taken place.

~~~
mercer
In the long run I think we're more likely to end up with a full js-based
styling approach that, similar to JSX, might look like CSS but really directly
styles individual nodes and 'manages' them.

But this is probably quite a ways off.

~~~
bastawhiz
The tricky part is handling things like hover states and pseudoelements. I
think scoped CSS and shadow DOM (and other new techniques) will probably be
the key to making this work long-term.

------
tambourine_man
Didn't know about all of those units. q, mm, cm… scientific notation?!

Also didn't know one could use counters already. Browser support is great. I
thought it was still under approval.

Amazing stuff, thanks

~~~
bastawhiz
CSS is a far bigger spec than anyone knows. Did you know that you can put dots
and spaces in your CSS classnames? Bonus points if you can figure out how to
escape characters in CSS identifiers ;)

~~~
tambourine_man
That I did know.

But scientific notation? C'mon

------
fleetfox
Can someone provide some hard numbers from real projects as to is it really
worth it assuming we can gzip/brotili?

~~~
diamondo25
Don't forget that gzip/brotli only affects the shipping time. This would be
the process:

    
    
      1. Server: check Accept-encoding header for gzip or brotili support
      2. Server: compress either brotli or gzipped file, or fall back to a raw file
      3. Server: send data to client
      4. Client: receive (and decompress, if not raw)
      5. Client: parse (big) resource
    

Also, compression through uglifying/minifying improves parse speed, which is
really helpful on (old) mobile devices. Adding compression through gzip or
brotli introduces additional overhead, because the uncompressing step will be
in-memory and stalls the processing of the file.

~~~
the8472
> 2\. compress

No, you don't need to waste CPU cycles on compression for each connection. You
can store the .css.gz on the filesystem along with the .css and have the
webserver pick up the appropriate file based on Accept-encoding.

That way you can precompress with the slowest compression options.

~~~
diamondo25
Of course, there are multiple ways to optimize it (like storing stuff at a
CDN), but I'm pretty sure 95% of the people do not precompress their assets.

------
wyldfire
If folks tend to use some higher level abstraction (isn't that what SASS and
LESS are?) maybe it makes sense to provide a new way to encode the information
in CSS. Similar to how WASM is supposed to be easier to parse than JavaScript,
right?

------
buster
I liked the writing style, fun read AND very informative!

~~~
remy_luisant
My pleasure, I'm glad you liked it! :)

------
WhitneyLand
Are there any good tools for deobfuscating css/js if you want to study a
technique used on some web page?

~~~
bastawhiz
If you're using Crass, it has a --pretty flag that will pretty-print your CSS,
even after minification. You can play with it online here, too:

[http://www.mattbasta.com/crass/](http://www.mattbasta.com/crass/)

------
bgrohman
I like your site design. Very clean and readable.

~~~
remy_luisant
Aww... Thanks!

My pleasure! All from scratch, designed for nothing but readability.

I am building textbooks on the same code, so the blog is a great stress and
user test.

------
cperciva
_I 'm for hire now. Le Sigh. Email's in the footer._

Remy: I'd suggest posting a CV and linking to it from this post. I looked and
couldn't find one anywhere on your site; you'll get a lot more qualified
interest if people can find out more about you than just a few blog posts.

~~~
remy_luisant
I thought about it, but I'm way too shy for that.

Not like it would lead to anywhere either, you know. :P

Two years of teaching university, MSc in computing, love of automation,
combinatiorial optimization without any significant amount of deep math skill,
circuit design, gate array stuff, low-level CPU optimization stuff, hardware
counters, microcontrollers, SQLite, Julia language, C, shell, a bunch more
programming languages, basic CSS and HTML, Mustache templates, Linux. No
JavaScript. The whole of luisant.ca is done by hand and from scratch, so you
can see what I can do with that. Also statistics.

I'm uncommonly silly and not at all serious, while still standing up for what
I believe is right, even if everyone disagrees with me. I do integrity though
and while I can stand my ground, I will yield to good evidence any day.

I wear goofy clothes to work, usually very colourful stuff. Don't expect
conformity.

And I have no love greater than the one for the cause of nature conservation,
and all research that goes with that.

That's about me in a nutshell.

Told you nothing will come of it. :P

~~~
xentronium
Man, just post a link to CV like you're advised and let good things happen to
you. If they don't, you lose nothing, but if they do, you got something out of
your effort.

~~~
cfqycwz
Seriously, somebody saw he's looking for a job, and _was actually looking for
his CV as somebody in charge of hiring might do_

