diff --git a/History.md b/History.md index 9cb039668..200be5975 100644 --- a/History.md +++ b/History.md @@ -14,6 +14,7 @@ * Fixed issue [#184](https://github.com/GoalSmashers/clean-css/issues/184) - uses `!important` for optimization opportunities. * Fixed issue [#190](https://github.com/GoalSmashers/clean-css/issues/190) - uses shorthand to override another shorthand. * Fixed issue [#197](https://github.com/GoalSmashers/clean-css/issues/197) - adds borders merging by understandability. +* Fixed issue [#210](https://github.com/GoalSmashers/clean-css/issues/210) - adds temporary workaround for aggressive merging. * Fixed issue [#246](https://github.com/GoalSmashers/clean-css/issues/246) - removes IE hacks when not in compatibility mode. * Fixed issue [#247](https://github.com/GoalSmashers/clean-css/issues/247) - removes deprecated `selectorsMergeMode` switch. * Refixed issue [#250](https://github.com/GoalSmashers/clean-css/issues/250) - based on new quotation marks removal. diff --git a/README.md b/README.md index 79d1979b6..ad2e27084 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ cleancss [options] source-file, [source-file, ...] --skip-rebase Disable URLs rebasing --skip-advanced Disable advanced optimizations - selector & property merging, reduction, etc. +--skip-aggressive-merging Disable properties merging based on their order --rounding-precision [value] Rounding precision, defaults to 2 -c, --compatibility [ie7|ie8] Force compatibility mode -d, --debug Shows debug information (minification time & compression efficiency) diff --git a/bin/cleancss b/bin/cleancss index 8def84dca..c3f2c2ab5 100755 --- a/bin/cleancss +++ b/bin/cleancss @@ -24,6 +24,7 @@ commands .option('-s, --skip-import', 'Disable @import processing') .option('--skip-rebase', 'Disable URLs rebasing') .option('--skip-advanced', 'Disable advanced optimizations - selector & property merging, reduction, etc.') + .option('--skip-aggressive-merging', 'Disable properties merging based on their order') .option('--rounding-precision [value]', 'Rounding precision, defaults to 2', parseInt) .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode') .option('-t, --timeout [seconds]', 'Per connection timeout when fetching remote @imports (defaults to 5 seconds)') @@ -75,6 +76,8 @@ if (commands.skipRebase) cleanOptions.noRebase = true; if (commands.skipAdvanced) cleanOptions.noAdvanced = true; +if (commands.skipAggressiveMerging) + cleanOptions.noAggressiveMerging = true; if (commands.compatibility) cleanOptions.compatibility = commands.compatibility; if (commands.roundingPrecision !== undefined) diff --git a/lib/clean.js b/lib/clean.js index c27607616..bc4bb392a 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -343,7 +343,8 @@ var minify = function(data, callback) { data = new SelectorsOptimizer(data, context, { keepBreaks: options.keepBreaks, lineBreak: lineBreak, - compatibility: options.compatibility + compatibility: options.compatibility, + aggressiveMerging: !options.noAggressiveMerging }).process(); }); } diff --git a/lib/properties/optimizer.js b/lib/properties/optimizer.js index 1de04479b..aea10b5b9 100644 --- a/lib/properties/optimizer.js +++ b/lib/properties/optimizer.js @@ -3,7 +3,7 @@ var processableInfo = require('./processable'); var overrideCompactor = require('./override-compactor'); var shorthandCompactor = require('./shorthand-compactor'); -module.exports = function Optimizer(compatibility) { +module.exports = function Optimizer(compatibility, aggressiveMerging) { var overridable = { 'animation-delay': ['animation'], 'animation-direction': ['animation'], @@ -187,7 +187,7 @@ module.exports = function Optimizer(compatibility) { // e.g. a{display:inline-block;display:-moz-inline-box} // however if `mergeablePosition` yields true then the rule does not apply // (e.g merging two adjacent selectors: `a{display:block}a{display:block}`) - if (_property != lastProperty || mergeablePosition(i)) { + if (aggressiveMerging && _property != lastProperty || mergeablePosition(i)) { while (true) { toOverridePosition = properties.indexOf(_property, toOverridePosition); if (toOverridePosition == -1) diff --git a/lib/selectors/optimizer.js b/lib/selectors/optimizer.js index 25f1c3103..d7d5167b5 100644 --- a/lib/selectors/optimizer.js +++ b/lib/selectors/optimizer.js @@ -10,7 +10,7 @@ module.exports = function Optimizer(data, context, options) { var minificationsMade = []; - var propertyOptimizer = new PropertyOptimizer(options.compatibility); + var propertyOptimizer = new PropertyOptimizer(options.compatibility, options.aggressiveMerging); var cleanUpSelector = function(selectors) { if (selectors.indexOf(',') == -1) diff --git a/test/binary-test.js b/test/binary-test.js index e9731a378..3927e8633 100644 --- a/test/binary-test.js +++ b/test/binary-test.js @@ -307,5 +307,17 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({ assert.equal(stdout, 'div{width:1px}'); } }) + }, + 'neighbour merging': { + 'of (yet) unmergeable properties': pipedContext('a{display:inline-block;color:red;display:-moz-block}', '--skip-aggressive-merging', { + 'gets right result': function(error, stdout) { + assert.equal(stdout, 'a{display:inline-block;color:red;display:-moz-block}'); + } + }), + 'of mergeable properties': pipedContext('a{background:red;display:block;background:white}', '--skip-aggressive-merging', { + 'gets right result': function(error, stdout) { + assert.equal(stdout, 'a{display:block;background:#fff}'); + } + }) } }); diff --git a/test/unit-test.js b/test/unit-test.js index 3d129da76..83f833fa4 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -1452,6 +1452,13 @@ title']{display:block}", 'a{display:none;border:1px solid #fff!important}' ] }), + 'duplicate properties with aggressive merging disabled': cssContext({ + 'of (yet) unmergeable properties': 'a{display:inline-block;color:red;display:-moz-block}', + 'of mergeable properties': [ + 'a{background:red;display:block;background:white}', + 'a{display:block;background:#fff}' + ] + }, { noAggressiveMerging: true }), 'same selectors': cssContext({ 'of two non-adjacent selectors': '.one{color:red}.two{color:#00f}.one{font-weight:700}', 'of two adjacent single selectors': [