24 ms·
CSS Reminification: A crazy idea that worked
- martijndeh 10y agoI'm curious though, how do these minifications, or CSS minifications in general, affect runtime performance? Reducing the file size is great, and a goal in itself (though brotli is more important where gzip is supported), but another important goal is rendering the page fast. Some CSS selectors are faster than others, is this something minifiers take into account? Or is this not significant at all?
- Etheryte 10y agoChanging selectors would be an unsafe transform (how could the minifier know that the new selector matches the DOM?) and it's not related at all. Even if it was, selector speed isn't really relevant, the changes are way too miniscule.
- ldev 10y agoNow I know why most of my colleagues in software development do not have a degree - academy really, really closes your mind in some strange bubble and shields you from real world... This article - I don't even...
- barrystaes 10y agoFilesize is not necessarily better performance. On todays hardware i believe (but i have not tested this..) that opening a zipped 1MB file often is slower than just opening it directly, basically thats just shoving it in RAM.
- jo909 10y agoOn the contrary, reading over the network or from disk (no matter how fast and modern) is still comparatively slow and is nearly always the bottleneck. Most non-embedded CPUs are more than fast enough to decompress every bit they get from the network or disk without decompression becoming the new bottleneck. There are other factors like latency, seeking, the minimum block size, and it always depends on the application, but generally speaking reading and writing compressed data should always be considered. That being said, for CSS the benchmark should rather be the size after gzip or other commonly used HTTP-Stream compressions, which are almost universally used anyway.
- rocqua 10y agoCompression and HTTPS don't play nice together though. So in cases where every byte matters, and you can't get rid of HTTPS (an admittedly rather niche use case). This minification still has some uses.
- jo909 10y agoIf you are talking about the BREACH vulerability, CSS won't reflect user input. The attacker is not able to observe thousands of slight variations of the same file, which is how this attack works (simplified). Transferring static files compressed over HTTPS is completely safe to my knowledge. So maybe if you inline your CSS into the page this comes into play. Also I never said minification is useless, only that you need to compare plain+gzip vs minifier1+gzip vs minifier2+gzip to see the _effective_ size reduction.
- deleted 10y ago[deleted]
- snsr 10y ago> If lossy CSS minification is a thing that we are willing to put up with I'm not, neat experiment though.
- tpetry 10y agoThe problem with such a tree optimization is that you will only find a locally best solution. If compressor1 generates the smallest result in step 1 all other compressors will only try to minimize this result. But maybe the compressor did something which the other conpressors are not optimized for. So you'll find a lically best solution for a starting point with conpressor1. But maybe it would have been better to start with compressor3 because it's result is smaller after step 2 than starting with compressor1.
- tambourine_man 10y agoGood… (read in Palpatine's voice) Now rewrite all your selectors in optimum precedence and specificity for file size. After that, remember that it will all go through gzip, so let's see how reordering properties affect compression.
- leni536 10y agoAnd what's the size difference comparing the gzipped css files?
- destructionator 10y ago`rm bootstrap.css` look, a 100% reduction! And it led to a better website. `gzip goodfile.css` and there's an improvement several times more effective than even the best minifier. And it keeps your source code legible in the browser and doesn't require a slow/buggy asset pipeline to test changes. Yes, yes, I know minify+gzip can save like an additional 1% over what gzip alone does. To me, that's just not worth the cost to the developer.
- cphoover 10y agoOne of the main points of css optimization is not transfer size, but the time it takes the css engine to parse through a css file, and figure out where to apply those changes to the DOM. I think that while the described "reminification" method may not make sense in practice (as other's have said running minification process multiple times will amplify minifier bugs), Optimizing CSS, removing unused rules, grouping similar rules, optimizing selectors etc... does make sense, regardless of reduction amount in comparison to compression.
- xtf 10y agoAnd then HTTP/2 helps more, because it does not open a new connection for each file.
- motoboi 10y agoAnd because the compression session is longer and has a bigger dictionary. And because the TCP window size is already maximized.
- destructionator 10y agoHTTP 1.1 also does not open a new connection for each file.
- SippinLean 10y ago>And it led to a better website. Where I had to write and test a modal by scratch? That's a loss of time and money for no benefit. >it keeps your source code legible That's what Sass sourcemaps and source-beautifying browser plugins are for >that's just not worth the cost to the developer It's part of my build, it costs me nothing.
- Brockenstein 10y ago"It took 25 extra minutes to save this 261 bytes. Worth it? You decide." I think I've decided it's obviously not worth it, even if we built a time machine and sent the css back to 1955 when they'd appreciate 261 bytes difference. (Granted they had no use for CSS in 1955).
- SZJX 10y agoThis just makes no sense. If somehow the minimizer wasn't able to further process it, maybe it's just because it was already quite thoroughly processed and you will loss some information if you continue? That's totally unsound approach. What does that extra fee bytes of saving do to loading time anyways? Probably very little, yet you risk very real degradation and broken behaviors. Not to mention the author even admitted to not being very proficient in CSS and doesn't even want to learn JS because he "dislikes it too much"... The whole description of the process is basically dragging something on out of very little substance. In general good laughing material though, just as he acknowledged at the end of the article, I guess.
- huula 10y agoTransforming .a-really-long-class-name-or-id into something shorter, like .x would save a lot more bytes. Another thing is splicing unecessary properties, which can even save more bytes, but given web apps becoming becoming so dynamic right now, that would be hard or really awkward for developer to work with too.
- saagarjha 10y agoOh, is that why I see websites like Facebook and Google using ids like .u-123-gz instead of something like .search-bar?
- ht85 10y agoThat's only a secondary reason, the main reason for this is to avoid having to deal with CSS' "everything is global" flaw. CSS Modules [1] and other tools allow you to require CSS like you would with any other dependency, and replace named classes by unique hashes at build time. This prevents your CSS from leaking to elements that do not explicitly require it. [1] https://github.com/css-modules/css-modules https://github.com/css-modules/css-modules
- gkoberger 10y agoThis isn't something a minifier could do without also modifying HTML and JS, and since a lot of JS automatically generates CSS names (something like $(`.list-${i}`)), this would be nearly impossible. The programmer could shorten it when writing, but is the extra half a milisecond worth having to work with x, y and z as classes rather than more explicit classes?
- ht85 10y agoMaybe I'm misunderstanding your example, are you trying to emulate `.nth-child(x)` with classes like `.list-1`, `.list-2`? If that's the case, using CSS Modules, you can do in CSS: .list-1 { ... } .list-2 { ... } requiring it will yield a map like this: { 'list-1': 'JSNF4S12', 'list-2': 'IE945JSN' } which you can use this way: const styles = require('file.css'); $('.' + styles[`list-${i}`]) // effectively $('.JSNF4S12')
- vmarsy 10y agoThis is pretty cool! > Are the current CSS minifiers correct? > I handle crashing minifiers, as well as ones that loop forever. It could actually be useful to know the exact css before running the minifier who crashed/got stuck. One could check with a css validator if this is correct css in the first place (if not, one of the previous minifier screwed up) , and if so, inform the minifier's maintainers of their tool crashing with this particular valid input.
- simcop2387 10y ago> It could actually be useful to know the exact css before running the minifier who crashed/got stuck. I was actually thinking this could be used to speed up computation a bit too. If you're going to add a set of minifiers to the end of the chain, caching the intermediate results (really just the last one) would let you avoid reprocessing from scratch each time you need to do cssnano | cssnano | csso | *, I don't know if it does this now but the description didn't talk about it either. That'd let you look at the chain and find where a mistake propagated from.
- pg_is_a_butt 10y ago... every CSS file that I threw it its direction... it its? you almost made it through the first sentence without a typo. i trust your code as much. you're all idiots.
- sbierwagen 10y agoIf you really want to get fancy you could use Selenium to get screenshots and compare them to check that the remynified CSS produces the same layout as the original CSS. http://www.seleniumhq.org/ http://www.seleniumhq.org/
- make3 10y agorunning one instance for each combination for each targeted browser and browser version, lol. this would take forever
- make3 10y agorunning one instance for each combination for each targeted browser and browser version, lol. this would take forever
- Khalos 10y agoThis would be great, but would probably significantly hurt performance. Especially if media queries come into play and we'd have to try different resolutions and ensure they're all the same.
- chiefofgxbxl 10y agoTo add to that point, if you manage to get screenshots you can do an image comparison using perceptual hashing [0]. The idea is to compute hashes of images and compare those, rather than scanning through each pixel. Note that perceptual hashes should not obey the avalanche effect, so a minor difference in the two images should yield a small change in the hashes (desirable in this case). Then accept results that are within some small % error margin. An example of a library that does this is jimp [1]. [0] https://en.wikipedia.org/wiki/Perceptual_hashing https://en.wikipedia.org/wiki/Perceptual_hashing [1] https://github.com/oliver-moran/jimp#comparing-images https://github.com/oliver-moran/jimp#comparing-images
- xiamx 10y agoGreat work! There are several directions where you can make your work more substantial. For once it would be interesting to see what's the marginal benefit of iterative minification over iterations (can be represented in a graph). Does Remynification approach an asymptotic size value, will further minification actually increase the size instead of decreasing? Also, it would be interesting to take screenshot using selenium as suggested by sbierwagen and see if Remynification actually preserves initial layout. Lastly, it would be interesting to see a theory proposed as why such method work, and what can future minifier learn from this.
- kzrdude 10y agoChaining was not exactly the level of innovation that the introduction set up for.
- remy_luisant 10y agoI'm an academic. I get very unwell if I'm not pompous at least half of the time. I also had two days to put this together, from conception to submission here. I could have been more innovative, but given the time limit... The best part was that the whole description is technically correct.
- ars 10y agoYou should apply this to png optimization. A combination of: optipng, pngout, pngcrush, DeflOpt, advpng. It's a bit more complicated since you have to also vary the command line arguments you pass to the program. (Different color types can sometimes help, as can different filters.)
- masklinn 10y agoThat's a pretty old tech. So old that many existing software package do that for you e.g. ImageOptim for OSX will run all of Zopfli, PNGOUT, OptiPNG, AdvPNG and PNGCrush using a nice drag-and-drop interface.
- nailer 10y agoIt does SVG now too! (Edit: heart, why doesn't HN support emoji?) ImageOptim
- tambourine_man 10y agoBecause we are grumpy old grey beards. And it wouldn't fit with the background color, of course. Can you imagine scrolling throught all that promiscuity of color and shape? Shivers. ASCII4ever!
- Exuma 10y agoYour site is very nicely styled and easy to read... I like how large and legible and clean-looking the font is. Also, your writing style is funny, nice work.
- nimchimpsky 10y agoha, I thought the site was horrible. Too big.
- carc1n0gen 10y agoThat's what I liked about it
- astrodust 10y agoHN: For all your constructive criticism needs.
- Exuma 10y agoI would be extremely curious to find out what modifications were made by the minifiers in round 2 and onwards that it couldn't have caught the first time...? JS or HTML I suppose I could see, because they're more complicated, but CSS by itself is very simple, so I'm wondering what actually got left out. Do you have any diffs or info on what it was removing or doing?
- remy_luisant 10y agoNo, but you can do this yourself quite easily. I am way too tired and sleep deprived to do more on this for at least a couple of days. Even then I have other priorities.
- quink 10y agoI found that rearranging by desired output seemed to work better, especially once you consider that compression works best on repeated longer strings. With minification as it stands you're forced to have the longer strings once, with the short strings (the CSS properties) repeated a lot. This is exactly backwards from what you want. You want the short strings to appear infrequently, and the longer strings a lot. CSS resets sheets are a bad example for this kind of thing, as they're strongly sorted by desired output property, but for general CSS for something with a lot of components, for example, or a CSS sheet with page template specific styling, it seems like it should minify and gzip a lot better. Plus, you can group your CSS by relevant section, i.e. keep your colours separate from your alignment, from your fonts, etc. Except the problem is that doing it this way requires a bit of rearranging of the rules, which may cause some trouble in a fairly small number of cases, so that's why it's out as an automated way of minifying things.
- bgirard 10y agoThis doesn't explore where the additional savings are coming from so that they can be contributed back into minifiers.
- remy_luisant 10y agoPay me and I will do this. Otherwise I have to do my day job and my project that I will use to survive when my job finishes. I will even learn CSS and JS to a degree where I can contribute the patches myself.
- dullroar 10y ago"IT...COULD...WORK!!!" - Dr. Frederick Frankenstein Cool idea. Especially not reinventing wheels but chaining them together instead. Good work.
- SFJulie 10y agoLooking at modern websites: very few use the Accept-Encoding: gzip of the HTTP 1/1 This could even «minify the served CSS» a lot :) (ok client side it will always be as big, but the server side is often paying its traffic and the client side may too so it reduces traffic anyway and means great savings). For public static websites, the savings induced by gzip compression totally justify to not use http2 when traffic matters.
- icebraining 10y agoFor public static websites, the savings induced by gzip compression totally justify to not use http2 when traffic matters. What do you mean? You can use gzip in HTTP/2.
- quakenul 10y agoI really can't tell if this is satire. But either everyone is in on the joke and out to get naive people like me (in that case, well played) or Hacker News does not seem to think so. I don't think there is one single use case, on any scale, anywhere in the world, where saving up to 17% on a minimized css file before gzip would matter in the slightest, let alone while adding 20mins to your build cycle :)
- cobookman 10y agoSaving 17% on a the google.com, Facebook.com, and Amazon.com CSS files would make a difference. Now that also depends on what the TCP packet size is. For example saving 1Byte might not lessen the amount of network traffic needing to be sent.
- quakenul 10y agoI very much doubt 17% before gzip on a already minimized css file would make any meaningful difference, to anyone. Check out the compression example on https://css-tricks.com/the-difference-between-minification-and-gzipping/ https://css-tricks.com/the-difference-between-minification-a...
- underwater 10y agoThis discussion reminds me of this exploration into compressing JSON data. Unless you're considering the final gzipped size you're doing it wrong: "In short, if you try to eliminate redundancy by applying some kind of clever transformation or restructuring your data object before piping it to gzip, you will probably just do a crappy job of reimplementing gzip at the wrong layer of abstraction, and get worse results overall." -- https://github.com/wincent/relay/blob/hack/contrib/lightweight-results/README.md https://github.com/wincent/relay/blob/hack/contrib/lightweig...
- jordanwallwork 10y agoThat's a really good point. A minified that output code directly optimised to gzip efficiently would be a great thing
- plaguuuuuu 10y agoIn practice this is going to be gzipped before being sent over the wire right? What's the gzipped size difference? Something something entropy
- seanwilson 10y agoIt'll be smaller because gzip can only losslessly compress what is there but minifying first can lossfully remove characters like comments or with conversions like "0px" to "0".
- noway421 10y agoNot necessarily. jQuery for example decided against some uglify parameters because their gzipped version would have been bigger.
- BuuQu9hu 10y agoI worry that this is the chaos of folks not understanding compiler theory. This is the result: every minifier is a compiler, but none of these minifiers boast properties like idempotence and none of them are sufficiently correct that they achieve their goal on the first try. I don't expect to necessarily see scholarly papers, but I would not ever expect a minifier to improve on itself when run multiple times in a row!
- nbevans 10y agoYep. The first minifiers were just some regexes to do a search and replace. Undoubtably many nowadays are full tokenisers and build an AST - but I do suspect that there's still plenty of room for improvement.
- _delirium 10y agoIt's not that rare for optimizers to be able to find more optimizations in a subsequent pass. For example, it's often true (for at least small gains) in assembly peephole optimizers. Once you've applied one round of peephole optimizations, which are basically just simple pattern-matching replacing instruction sequences with better ones, the resulting, improved instruction sequence may now have new sequences that the peephole optimizer could improve again if run a second time. You could try running this iteratively until some kind of fixed point if compilation time were no issue... although, it might also have cycles! That is often the nature of these kinds of pattern-matching, heuristic optimization passes. That's especially likely if you mixed-and-matched from different compilers, like running optimization passes from gcc, clang, and icc interleaved with each other. Though that example would be difficult to do in practice, because they aren't source-to-source optimizers, and have totally different IRs, so can't easily be chained in the way these CSS-to-CSS optimizers can be chained.
- nine_k 10y agoThis is one of the problems with IT: it has too little science behind it. A lot of things are built based on common sense, tradition, and chutzpah. Much like building was in medieval times. No wonder things often crash and take a hard-to-predict time to build. Some things can be over-engineered but under-scienced, so to say, at the same time. A lot of great computer science already exists, and is applicable, and some of it is taught at universities. But it's not required for a CRUD app or for a flappy bird clone. And when you grow up enough to want more complex things, a lot is already forgotten.
- bluetwo 10y agoI am not a fan of css minimizers. I'm more a fan of writing compact, clean, logical css in the first place. A couple months ago I worked on a project and re-wrote a 129k minified css file someone created as a clean un-minified 12k css file that had 100% of the original functionality plus some additional UI improvements. You can only get these improvements if you understand what you are writing and stop using sass to write bloated files.
- TazeTSchnitzel 10y ago> I'm more a fan of writing compact, clean, logical css in the first place. Does your CSS completely lack whitespace and comments? If not, minification still has its use.
- scrollaway 10y agoIt sounds like you don't understand what a minifier is. A minifier takes your css code and removes the noise from it. It does so by removing whitespace, comments, duplicate rules and redundant properties. What it sounds like you're really complaining about is using sass (which has a compressed output), because it removes a layer of abstraction and makes it easy to shoot yourself in the foot. This is true of almost anything and everything.
- lukaszkups 10y ago99% this
- nkkollaw 10y agoCan't do that with Bootstrap and the like...
- minitech 10y agoThe two things aren’t exclusive. What reason do you have not to minify your compact, clean, logical CSS?
- dahart 10y agoI totally read the title as "Remnification" and "Remnyfication". I didn't see the right spelling until I got to section 5! "OH! RE-minification"... ;) Very nice, this is a fun project and a nice write up. I would definitely worry about lossy minification on production code, I've bumped into many minifier bugs that broke my valid CSS. Also, pretty sure you could get Bootstrap.css down to a couple k-bytes and really truly pwn the file size leaderboard if you could dead-strip all the rules not actually referenced in your HTML & JS.
- TazeTSchnitzel 10y agoMentioned elsewhere in these comments, uncss does that.
- Falkon1313 10y agoThis is a good point. On any sizable site, especially one that has evolved over time, you can't really remove CSS, it just gradually accretes more and more. But most of the rules aren't even used on most pages. Being able to first remove anything not used, then remove anything that gets overridden in the cascade, could reduce CSS down to a tiny fraction of its full size (never mind comments and spacing). But would that give better results than loading a big bloated and wasteful CSS file once and caching it for the entire site (or many sites in a case like CDN'd Bootstrap)? Either way is one form of bloat and waste or another.
- bastawhiz 10y agoAuthor of crass here. I wouldn't recommend doing what the author suggests. crass doesn't squeak out extra bytes when you reprocess because it already does this for you. If you combine multiple minifiers, the bugs in one minifier can end up being amplified by the others. For instance, one minifier might not consider !important when moving around CSS. Another minifier might then take that output and perform an optimization that's no longer just unsafe, but now incorrect. It might even delete rulesets that it believes are not used, ruining your stylesheet. There are suites that test the correctness of minifieres, and many don't do great. CSS still "works" when the syntax is invalid, so invalid stylesheets result in undefined results when you minify. Between bugs and undefined behavior, I wouldn't recommend mixing and matching just to save one or two TCP packets, especially with gzip/brotli on the wire.
- loop0 10y agoEven with one pass of a minifier it's possible to get bugs, so I wouldn't recommend reprocessing either.
- bastawhiz 10y agoReprocessing one minifier's output with itself is probably fine, since you're not mixing and matching approaches to minification. It's likely that a minifier is consistent with how it minifies internally, and they simply don't do multiple passes. Your time would be far better spent, though, making a pull request to properly implement multiple passes on your minifier of choice so that you can safely get that benefit. Or you could say "meh, I'm not losing sleep over the extra hundred bytes" and work on something more productive.
- deleted 10y ago[deleted]
- remy_luisant 10y agoI'm not recommending doing it either! :)
- 10y ago
- znpy 10y agoI wonder what the impacts of (re|)minification is on actual network performance. For example: consider a minified file x. X is likely getting gzipped when served. Is the reminified version smaller than the original? Same size? Bigger? You might expect the obvious answer, but did anyone do the actual measurements?
- remy_luisant 10y agoIt is a plan for a followup post to have that.
- rodrigocoelho 10y agoWhat really reduces css filesize for me is uncss[0]. It removes the unused styles and then I run the css through a minifier to finish the job. [0] https://github.com/giakki/uncss https://github.com/giakki/uncss
- bikamonki 10y agoI'm sorry, I have to: http://motherfuckingwebsite.com http://motherfuckingwebsite.com
- sAbakumoff 10y ago>> There is a catch: Remynification takes forever and may break your CSS, even though this isn't really my fault. Stopped reading after this line.
- beefsack 10y agoIt's an interesting experiment, not some sort of production recommendation.
- nimchimpsky 10y ago> It's an interesting experiment debatable, its a waste of time imo
- astrodust 10y agoFrom experiments we learn things. That is not time wasted.
- sAbakumoff 10y agoYes, of course, but to me this phrase means: "I conducted the experiment and you can reproduce it, but it can run forever and break your stuff". That hardly sounds like an enticing introduction.
- remy_luisant 10y agoIt isn't meant to be enticing, but factual. It will break stuff. It will run forever. The software that I committed works in theory, but I don't think you should actually deploy it in its current form. If you aren't interested in some playful carnage on a slow news day, no worries. Different strokes, eh? :)
- sAbakumoff 10y agoAlso "this isn't really my fault" might be a buzzkill.
- cjhanks 10y agoDoes your "reminified" CSS actually compress better under GZIP than any of the independent minifiers? The variance you were seeing looks to be irrelevant in comparison.
- remy_luisant 10y agoI really should be doing something else, but this is too interesting. It doesn't yet, but it could. Keep it mind, at the worst case scenario I get to pick which of the four individual minifiers I run. I will always at least be able to match the best one. There is absolutely nothing that prevents me from running zopfli over the final outputs and comparing the sizes. I can use the compressed size to drive search. A matter of a change in metric used to consider what is an improvement. I'll add this to my todo list on this project. Looks like I may be doing more on this than I originally intended...
- barrystaes 10y agoAnd while at that, load it PhantomJS and measure parse and render time. Then try to figure out what weight to give bandwidth VS cpu performance, realize other things can hog the cpu, get an icecream and give up.
- Galanwe 10y agoMinimizing the lossfull minifier from: #!/bin/bash rm -rf $1 touch $1 to #!/bin/sh >"$1" Your turn, reddit
- TazeTSchnitzel 10y ago$ ln -s /usr/bin/true ~/bin/cssmin $ cssmin < in.css > out.css
- d--b 10y agoRemy, you forgot the y in remynification in the submission title. Cause it's all about you after all! :)