Use natural sort for sorting selectors #425

Closed
cvrebert opened this Issue Dec 29, 2014 · 9 comments

Projects

None yet

5 participants

@cvrebert

It appears that clean-css now sorts selectors, whereas it didn't previously.
It seems to be using a simple naive sort, which has somewhat unpleasant results when the selectors have numbers in them. For example:

.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9 {...}

Would it be possible to use natural sorting instead, to obtain more pleasant results? For example:

.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12 {...}

Here are a couple libs I found on npm that might do the job:

@cvrebert cvrebert referenced this issue in twbs/bootstrap Dec 29, 2014
Merged

Bump grunt-contrib-cssmin to ~0.11.0 #15456

@jakubpawlowicz
Owner

@cvrebert in general we don't care how nice the output is. It just has to be as small as possible. However does it sound any similar to #209?

@DavidOliver

Can sorting of selectors be turned off? This is a problem for link, visited, hover, focus and active state selectors, which sometimes need to be in a certain order because of specificity.

I've just updated the npm modules in a project including gulp-minify-css which uses clean-css, and I'm getting unwanted reordering. Example:

Old version:

.Button--disabled:hover,.Button--disabled:focus,.Button--disabled:active{color:#999894!important}

New version:

.Button--disabled:active,.Button--disabled:focus,.Button--disabled:hover{color:#999894!important}

I've tried using all the options documented in the readme but haven't managed to turn ordering off.

@jakubpawlowicz
Owner

@DavidOliver Sorting is there to aid optimizations, but let's see what we can do. In the meantime could you post a quick demo showing the different behavior based on order? Thanks!

@DavidOliver

@jakubpawlowicz, thanks for your reply. It turns out I was being an idiot and hadn't twigged that because the reordering is done per selector block it doesn't matter.

@jakubpawlowicz
Owner

It's done per selector indeed. No worries, cheers!

@ben-eb
ben-eb commented Mar 9, 2015

It's likely that if selectors are sorted by natural sorting, then consequent selectors can be gzipped more effectively. In this somewhat contrived example:

.col-3, .col-2, .col-4, .col-1, .col-10 {
    display: block;
}

.col-1, .col-2 {
    float: left;
}

Can be:

.col-1, .col-2, .col-3, .col-4, .col-10 {
    display: block;
}

.col-1, .col-2 {
    float: left;
}

.col-1, .col-2 is now an identifier that can be compressed across both blocks, whereas before gzip would have .col-1 & .col-2 as separate identifiers. It's a very minor point but it could potentially help deliver a smaller gzipped file.

@jessehouchins

For what it's worth, I would really like to have been able to disable the sorting feature when converting a project from compass (which did not sort selectors like this). I completely understand why the sorting feature exists, of course, and I would leave it on for the final production build. But durring the conversion, the sorting made the diff huge and complex to review.

@jakubpawlowicz
Owner

Thanks @jessehouchins for your input. I'm still considering it and leaving it open as an enhancement.

@jakubpawlowicz jakubpawlowicz modified the milestone: 4.0 Jan 4, 2017
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 10, 2017
@jakubpawlowicz See #425 - adds natural sorting algorithm.
Why:

* We need it to sort selectors accordingly.
08bcc20
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 10, 2017
@jakubpawlowicz Fixes #425 - enables natural method of sorting selectors.
Still defaults to standard sorting but natural becomes
a new option. Controlled via `selectorsSortingMethod`
option in level 1 optimizations.

Why:

* Natural way could be a more compression-efficient way;
* it's easier to read for a human.
be8fb59
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 11, 2017
@jakubpawlowicz See #425 - nitpicking natural sorting algorithm.
Thanks to @alexlamsl for spotting these.
44d6b24
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 11, 2017
@jakubpawlowicz See #425 - adds natural sorting algorithm.
Why:

* We need it to sort selectors accordingly.
7b2b357
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 11, 2017
@jakubpawlowicz See #425 - nitpicking natural sorting algorithm.
Thanks to @alexlamsl for spotting these.
314235e
@jakubpawlowicz jakubpawlowicz added a commit that closed this issue Jan 11, 2017
@jakubpawlowicz Fixes #425 - enables natural method of sorting selectors.
Still defaults to standard sorting but natural becomes
a new option. Controlled via `selectorsSortingMethod`
option in level 1 optimizations.

Why:

* Natural way could be a more compression-efficient way;
* it's easier to read for a human.
d0320e8
@jakubpawlowicz jakubpawlowicz added a commit that referenced this issue Jan 11, 2017
@jakubpawlowicz See #425 - nitpicking natural sorting algorithm.
Thanks to @alexlamsl for spotting these.
68f4bd7
@jakubpawlowicz
Owner

Ready on master and soon in 4.0. Available via:

// API
new CleanCSS({ level: { 1: { selectorsSortingMethod: 'natural' } } }).minify(...)
# CLI
%> cleancss -O1 selectorsSortingMethod:natural ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment