From: Jakub Pawlowicz Date: Tue, 6 Jan 2015 19:16:57 +0000 (+0000) Subject: Adds better non-adjacent selector merging when body is the same. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=da4ea0086d0ee2140781ddaeba464990a3bf062c;p=clean-css.git Adds better non-adjacent selector merging when body is the same. * See #158. --- diff --git a/History.md b/History.md index c8a84624..b5582fc4 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,7 @@ ================== * Adds 0deg to 0 minification where possible. +* Adds better non-adjacent selector merging when body is the same. * Fixed issue [#182](https://github.com/GoalSmashers/clean-css/issues/182) - removing space after closing brace. [3.0.2 / 2015-01-04](https://github.com/jakubpawlowicz/clean-css/compare/v3.0.1...v3.0.2) diff --git a/lib/selectors/optimizers/advanced.js b/lib/selectors/optimizers/advanced.js index 6c3175ce..5b715696 100644 --- a/lib/selectors/optimizers/advanced.js +++ b/lib/selectors/optimizers/advanced.js @@ -19,6 +19,10 @@ function changeSelectorOf(token, newSelectors) { token.metadata.selectorsList = newSelectors.list; } +function unsafeSelector(value) { + return /\.|\*| :/.test(value); +} + AdvancedOptimizer.prototype.isSpecial = function (selector) { return this.options.compatibility.selectors.special.test(selector); }; @@ -255,6 +259,32 @@ AdvancedOptimizer.prototype.reduceSelector = function (tokens, selector, data, o } }; +AdvancedOptimizer.prototype.mergeNonAdjacentByBody = function (tokens) { + var candidates = {}; + + for (var i = tokens.length - 1; i >= 0; i--) { + var token = tokens[i]; + if (token.kind != 'selector') + continue; + + if (token.body.length > 0 && unsafeSelector(token.metadata.selector)) + candidates = {}; + + var oldToken = candidates[token.metadata.body]; + if (oldToken && !this.isSpecial(token.metadata.selector) && !this.isSpecial(oldToken.metadata.selector)) { + changeSelectorOf( + token, + CleanUp.selectors(oldToken.value.concat(token.value), false) + ); + + oldToken.body = []; + candidates[token.metadata.body] = null; + } + + candidates[token.metadata.body] = token; + } +}; + function optimizeProperties(tokens, propertyOptimizer) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; @@ -287,6 +317,8 @@ AdvancedOptimizer.prototype.optimize = function (tokens) { self.removeDuplicates(tokens); self.mergeAdjacent(tokens); + + self.mergeNonAdjacentByBody(tokens); } _optimize(tokens); diff --git a/test/fixtures/big-min.css b/test/fixtures/big-min.css index d301a647..fc8116b7 100644 --- a/test/fixtures/big-min.css +++ b/test/fixtures/big-min.css @@ -4,7 +4,7 @@ audio,canvas,video{display:inline-block} [hidden],audio:not([controls]){display:none} html{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} button,html,input,select,textarea{font-family:sans-serif} -body{margin:0} +body,figure,form{margin:0} a:focus{outline:dotted thin} a:active,a:hover{outline:0} h1,h2,h3,h4,h5,h6{margin:0;font-weight:700} @@ -27,7 +27,6 @@ dd{margin:0 0 0 40px} nav ol,nav ul{list-style:none} img{-ms-interpolation-mode:bicubic} svg:not(:root){overflow:hidden} -figure,form{margin:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0;white-space:normal} button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline} diff --git a/test/fixtures/blueprint-min.css b/test/fixtures/blueprint-min.css index fc00f149..3651f8fe 100644 --- a/test/fixtures/blueprint-min.css +++ b/test/fixtures/blueprint-min.css @@ -27,7 +27,7 @@ p .right{margin:1.5em 0 1.5em 1.5em;padding:0} a:focus,a:hover{color:#09f} a{color:#06c;text-decoration:underline} blockquote{margin:1.5em;color:#666;font-style:italic} -dfn,strong{font-weight:700} +dfn,dl dt,strong,th{font-weight:700} dfn,em{font-style:italic} sub,sup{line-height:0} abbr,acronym{border-bottom:1px dotted #666} @@ -40,10 +40,8 @@ ol,ul{margin:0 1.5em 1.5em 0;padding-left:1.5em} ul{list-style-type:disc} ol{list-style-type:decimal} dl{margin:0 0 1.5em} -dl dt{font-weight:700} dd{margin-left:1.5em} table{margin-bottom:1.4em;width:100%} -th{font-weight:700} thead th{background:#c3d9ff} caption,td,th{padding:4px 10px 4px 5px} tbody tr.even td,tbody tr:nth-child(even) td{background:#e5ecf9} diff --git a/test/integration-test.js b/test/integration-test.js index 568385f7..4886c505 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -1784,6 +1784,22 @@ title']{display:block}", 'with repeated selectors': [ '#zero>p,.one,.two{color:red}.two,#zero>p,.three{color:red}', '#zero>p,.one,.three,.two{color:red}' + ], + 'of element selectors': [ + 'p{color:red}a{color:#000}div{color:red}', + 'div,p{color:red}a{color:#000}' + ], + 'of element selectors inside @media': [ + '@media screen{p{color:red}a{color:#000}div{color:red}}', + '@media screen{div,p{color:red}a{color:#000}}' + ], + 'of element selectors with a class selector in between': [ + 'p{color:red}.a{color:#000}div{color:red}', + 'p{color:red}.a{color:#000}div{color:red}' + ], + 'of element selectors with an empty class selector in between': [ + 'p{color:red}.a{}div{color:red}', + 'div,p{color:red}' ] }), 'same bodies - IE8 compat': cssContext({