* Moves tokenizer code into lib/tokenizer.
* Moves URL scanner into lib/urls/reduce (was named incorrectly before).
* Moves URL rebasing & rewriting into lib/urls.
+* Fixed issue [#375](https://github.com/jakubpawlowicz/clean-css/issues/375) - unit compatibility switches.
* Fixed issue [#436](https://github.com/jakubpawlowicz/clean-css/issues/436) - refactors URI rewriting.
* Fixed issue [#448](https://github.com/jakubpawlowicz/clean-css/issues/448) - rebasing no protocol URIs.
* Fixed issue [#517](https://github.com/jakubpawlowicz/clean-css/issues/517) - turning off color optimizations.
* `'[+-]selectors.adjacentSpace'` - turn on / off extra space before `nav` element
* `'[+-]selectors.ie7Hack'` - turn on / off IE7 selector hack removal (`*+html...`)
* `'[+-]selectors.special'` - a regular expression with all special, unmergeable selectors (leave it empty unless you know what you are doing)
+* `'[+-]units.ch'` - turn on / off treating `ch` as a proper unit
* `'[+-]units.rem'` - turn on / off treating `rem` as a proper unit
+* `'[+-]units.vh'` - turn on / off treating `vh` as a proper unit
+* `'[+-]units.vm'` - turn on / off treating `vm` as a proper unit
+* `'[+-]units.vmax'` - turn on / off treating `vmax` as a proper unit
+* `'[+-]units.vmin'` - turn on / off treating `vmin` as a proper unit
+* `'[+-]units.vm'` - turn on / off treating `vm` as a proper unit
-For example, this declaration `--compatibility 'ie8,+units.rem'` will ensure IE8 compatiblity while enabling `rem` units so the following style `margin:0px 0rem` can be shortened to `margin:0`, while in pure IE8 mode it can't be.
+For example, using `--compatibility 'ie8,+units.rem'` will ensure IE8 compatiblity while enabling `rem` units so the following style `margin:0px 0rem` can be shortened to `margin:0`, while in pure IE8 mode it can't be.
To pass a single off (-) switch in CLI please use the following syntax `--compatibility *,-units.rem`.
var Splitter = require('../utils/splitter');
var widthKeywords = ['thin', 'thick', 'medium', 'inherit', 'initial'];
-var allUnits = ['px', '%', 'em', 'rem', 'in', 'cm', 'mm', 'ex', 'pt', 'pc', 'vw', 'vh', 'vmin', 'vmax'];
+var allUnits = ['px', '%', 'em', 'in', 'cm', 'mm', 'ex', 'pt', 'pc', 'ch', 'rem', 'vh', 'vm', 'vmin', 'vmax', 'vw'];
var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + allUnits.join('|') + '|)|auto|inherit)';
var cssCalcRegexStr = '(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)';
var cssFunctionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(([A-Z]|[0-9]|\\ |\\,|\\#|\\+|\\-|\\%|\\.|\\(|\\))*\\)';
var listStylePositionKeywords = ['inside', 'outside', 'inherit'];
function Validator(compatibility) {
- if (compatibility.units.rem) {
- this.compatibleCssUnitRegex = cssUnitRegex;
- this.compatibleCssUnitAnyRegex = cssUnitAnyRegex;
- } else {
- var validUnits = allUnits.slice(0).filter(function (value) {
- return value != 'rem';
- });
-
- var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + ')|auto|inherit)';
- this.compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i');
- this.compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i');
- }
+ var validUnits = allUnits.slice(0).filter(function (value) {
+ return !(value in compatibility.units) || compatibility.units[value] === true;
+ });
+
+ var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)';
+ this.compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i');
+ this.compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i');
}
Validator.prototype.isValidHexColor = function (s) {
this.options = options;
var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
- if (options.compatibility.units.rem)
- units.push('rem');
- options.unitsRegexp = new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')', 'g');
+ var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw'];
+
+ otherUnits.forEach(function (unit) {
+ if (options.compatibility.units[unit])
+ units.push(unit);
+ });
+
+ options.unitsRegexp = new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g');
options.precision = {};
options.precision.value = options.roundingPrecision === undefined ?
if (/^(?:\-moz\-calc|\-webkit\-calc|calc)\(/.test(value))
return value;
- return value.replace(unitsRegexp, '$1' + '0');
+ return value
+ .replace(unitsRegexp, '$1' + '0' + '$2')
+ .replace(unitsRegexp, '$1' + '0' + '$2');
}
function multipleZerosMinifier(property) {
special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/ // special selectors which prevent merging
},
units: {
- rem: true
+ ch: true,
+ rem: true,
+ vh: true,
+ vm: true, // vm is vmin on IE9+ see https://developer.mozilla.org/en-US/docs/Web/CSS/length
+ vmax: true,
+ vmin: true,
+ vw: true
}
},
'ie8': {
special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/
},
units: {
- rem: false
+ ch: false,
+ rem: false,
+ vh: false,
+ vm: false,
+ vmax: false,
+ vmin: false,
+ vw: false
}
},
'ie7': {
special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/
},
units: {
- rem: false
+ ch: false,
+ rem: false,
+ vh: false,
+ vm: false,
+ vmax: false,
+ vmin: false,
+ vw: false,
}
}
};
'a{box-shadow:0 0 0 .15em #EBEBEB}'
],
'box shadow with three zeros and a value': 'a{box-shadow:0 0 0 15px #EBEBEB}',
- 'rems': [
- 'div{width:0rem;height:0rem}',
- 'div{width:0;height:0}'
- ],
'prefixed box shadow zeros': [
'a{-webkit-box-shadow:0 0 0 0; -moz-box-shadow:0 0 0 0}',
'a{-webkit-box-shadow:0 0;-moz-box-shadow:0 0}'
var Validator = require('../../lib/properties/validator');
var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata');
-var compatibility = new Compatibility().toOptions();
-var validator = new Validator(compatibility);
-function _optimize(source, mergeAdjacent, aggressiveMerging) {
+function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOptions) {
+ var compatibility = new Compatibility(compatibilityOptions).toOptions();
+ var validator = new Validator(compatibility);
+
var tokens = tokenize(source, {
options: {},
sourceTracker: new SourceTracker(),
[['border-top-width', false , false], ['calc(100%)']]
]);
}
+ },
+ 'understandable - non adjacent units': {
+ 'topic': 'a{margin-top:100px;padding-top:30px;margin-top:10vmin}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic, false, true), [
+ [['padding-top', false , false], ['30px']],
+ [['margin-top', false , false], ['10vmin']]
+ ]);
+ }
+ }
+ })
+ .addBatch({
+ 'understandable - non adjacent units in IE8 mode 123': {
+ 'topic': 'a{margin-top:100px;padding-top:30px;margin-top:10vmin}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic, false, true, 'ie8'), [
+ [['margin-top', false , false], ['100px']],
+ [['padding-top', false , false], ['30px']],
+ [['margin-top', false , false], ['10vmin']]
+ ]);
+ }
}
})
.export(module);
'div{transform:rotate(10deg) skew(.5deg)}',
[['transform', 'rotate(10deg)', 'skew(.5deg)']]
],
+ 'ch': [
+ 'div{width:0ch;height:0ch}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'rem': [
+ 'div{width:0rem;height:0rem}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'vh': [
+ 'div{width:0vh;height:0vh}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'vm': [
+ 'div{width:0vm;height:0vm}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'vmax': [
+ 'div{width:0vmax;height:0vmax}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'vmin': [
+ 'div{width:0vmin;height:0vmin}',
+ [['width', '0'], ['height', '0']]
+ ],
+ 'vw': [
+ 'div{width:0vw;height:0vw}',
+ [['width', '0'], ['height', '0']]
+ ],
'mixed units': [
'a{margin:0em 0rem 0px 0pt}',
[['margin', '0']]
],
- 'mixed vales': [
+ 'mixed values #1': [
'a{padding:10px 0em 30% 0rem}',
[['padding', '10px', '0', '30%', '0']]
],
+ 'mixed values #2': [
+ 'a{padding:10ch 0vm 30vmin 0vw}',
+ [['padding', '10ch', '0', '30vmin', '0']]
+ ],
'inside calc': [
'a{font-size:calc(100% + 0px)}',
[['font-size', 'calc(100% + 0px)']]
'a{margin:0em 0rem 0px 0pt}',
[['margin', '0', '0rem', '0', '0']]
],
- 'mixed vales': [
+ 'mixed values #1': [
'a{padding:10px 0em 30% 0rem}',
[['padding', '10px', '0', '30%', '0rem']]
+ ],
+ 'mixed values #2': [
+ 'a{padding:10ch 0vm 30vmin 0vw}',
+ [['padding', '10ch', '0vm', '30vmin', '0vw']]
]
}, { compatibility: 'ie8' })
)
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/);
+ assert.isTrue(options.units.ch);
assert.isTrue(options.units.rem);
+ assert.isTrue(options.units.vh);
+ assert.isTrue(options.units.vm);
+ assert.isTrue(options.units.vmax);
+ assert.isTrue(options.units.vmin);
+ assert.isTrue(options.units.vw);
}
},
'not given': {
},
'as a populated hash': {
'topic': function () {
- return new Compatibility({ units: { rem: false }, properties: { prefix: true } }).toOptions();
+ return new Compatibility({ units: { rem: false, vmax: false }, properties: { prefix: true } }).toOptions();
},
'gets merged options': function(options) {
assert.isTrue(options.colors.opacity);
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/);
+ assert.isTrue(options.units.ch);
assert.isFalse(options.units.rem);
+ assert.isTrue(options.units.vh);
+ assert.isTrue(options.units.vm);
+ assert.isFalse(options.units.vmax);
+ assert.isTrue(options.units.vmin);
+ assert.isTrue(options.units.vw);
}
}
})
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/);
+ assert.isFalse(options.units.ch);
assert.isFalse(options.units.rem);
+ assert.isFalse(options.units.vh);
+ assert.isFalse(options.units.vm);
+ assert.isFalse(options.units.vmax);
+ assert.isFalse(options.units.vmin);
+ assert.isFalse(options.units.vw);
}
},
'as an ie7 template': {
assert.isFalse(options.selectors.adjacentSpace);
assert.isTrue(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/);
+ assert.isFalse(options.units.ch);
assert.isFalse(options.units.rem);
+ assert.isFalse(options.units.vh);
+ assert.isFalse(options.units.vm);
+ assert.isFalse(options.units.vmax);
+ assert.isFalse(options.units.vmin);
+ assert.isFalse(options.units.vw);
}
},
'as an unknown template': {
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/);
+ assert.isFalse(options.units.ch);
assert.isFalse(options.units.rem);
+ assert.isFalse(options.units.vh);
+ assert.isFalse(options.units.vm);
+ assert.isFalse(options.units.vmax);
+ assert.isFalse(options.units.vmin);
+ assert.isFalse(options.units.vw);
}
},
'as a single string value without group': {
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/);
- assert.isTrue(options.units.rem); }
+ assert.isTrue(options.units.ch);
+ assert.isTrue(options.units.rem);
+ assert.isTrue(options.units.vh);
+ assert.isTrue(options.units.vm);
+ assert.isTrue(options.units.vmax);
+ assert.isTrue(options.units.vmin);
+ assert.isTrue(options.units.vw);
+ }
},
'as a complex string value without group': {
'topic': function () {
assert.isFalse(options.selectors.adjacentSpace);
assert.isFalse(options.selectors.ie7Hack);
assert.deepEqual(options.selectors.special, /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/);
+ assert.isTrue(options.units.ch);
assert.isFalse(options.units.rem);
+ assert.isTrue(options.units.vh);
+ assert.isTrue(options.units.vm);
+ assert.isTrue(options.units.vmax);
+ assert.isTrue(options.units.vmin);
+ assert.isTrue(options.units.vw);
}
}
})