From 3b8daf1b02b2316becc7a413ebbe3cb8d1b86c8b Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sun, 27 Jul 2014 13:42:08 +0100 Subject: [PATCH] Fixes #322 - adds background-size support to advanced optimizer. --- History.md | 1 + lib/properties/processable.js | 44 ++++++++++++++++++++++++++--------- lib/properties/validator.js | 13 +++++++++++ test/data/issue-312-min.css | 2 +- test/unit-test.js | 28 +++++++++++++++------- 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/History.md b/History.md index c53d533f..3f921a26 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,7 @@ * Improved performance of advanced mode validators. * Fixed issue [#307](https://github.com/GoalSmashers/clean-css/issues/307) - background-color in muliple backgrounds. +* Fixed issue [#322](https://github.com/GoalSmashers/clean-css/issues/322) - adds background-size support. * Fixed issue [#323](https://github.com/GoalSmashers/clean-css/issues/323) - stripping variable references. * Fixed issue [#325](https://github.com/GoalSmashers/clean-css/issues/325) - removing invalid @charset declarations. diff --git a/lib/properties/processable.js b/lib/properties/processable.js index bea50764..9d3e0aea 100644 --- a/lib/properties/processable.js +++ b/lib/properties/processable.js @@ -163,17 +163,18 @@ module.exports = (function () { }; breakUp.background = function (token) { // Default values - var result = Token.makeDefaults(['background-image', 'background-position', 'background-repeat', 'background-attachment', 'background-color'], token.isImportant); + var result = Token.makeDefaults(['background-image', 'background-position', 'background-size', 'background-repeat', 'background-attachment', 'background-color'], token.isImportant); var image = result[0]; var position = result[1]; - var repeat = result[2]; - var attachment = result[3]; - var color = result[4]; + var size = result[2]; + var repeat = result[3]; + var attachment = result[4]; + var color = result[5]; // Take care of inherit if (token.value === 'inherit') { // NOTE: 'inherit' is not a valid value for background-attachment so there we'll leave the default value - color.value = image.value = repeat.value = position.value = attachment.value = 'inherit'; + color.value = image.value = repeat.value = position.value = size.value = attachment.value = 'inherit'; return result; } @@ -190,18 +191,32 @@ module.exports = (function () { attachment.value = currentPart; } else if (validator.isValidBackgroundRepeat(currentPart)) { repeat.value = currentPart; - } else if (validator.isValidBackgroundPosition(currentPart)) { + } else if (validator.isValidBackgroundPositionPart(currentPart) || validator.isValidBackgroundSizePart(currentPart)) { if (i > 0) { - var repeatedPosition = parts[i - 1] + ' ' + currentPart; - if (validator.isValidBackgroundPosition(repeatedPosition)) { + var previousPart = parts[i - 1]; + + if (previousPart.indexOf('/') > 0) { + var twoParts = new Splitter('/').split(previousPart); + size.value = twoParts.pop() + ' ' + currentPart; + parts[i - 1] = twoParts.pop(); + } else if (i > 1 && parts[i - 2] == '/') { + size.value = previousPart + ' ' + currentPart; + i -= 2; + } else if (parts[i - 1] == '/') { + size.value = currentPart; + position.value = previousPart; i--; - position.value = repeatedPosition; } else { - position.value = currentPart; + position.value = previousPart + ' ' + currentPart; + i--; } } else { position.value = currentPart; } + } else if (validator.isValidBackgroundPositionAndSize(currentPart)) { + var sizeValue = new Splitter('/').split(currentPart); + size.value = sizeValue.pop(); + position.value = sizeValue.pop(); } else if (validator.isValidColor(currentPart)) { color.value = currentPart; } else if (validator.isValidUrl(currentPart) || validator.isValidFunction(currentPart)) { @@ -429,7 +444,7 @@ module.exports = (function () { if (meta && meta.partsCount && meta.position < meta.partsCount - 1 && processable[token.prop].multiValueLastOnly) continue; - result.value += ' ' + token.value; + result.value += (processable[token.prop].prefixShorthandValueWith || ' ') + token.value; } result.value = result.value.trim(); @@ -596,6 +611,7 @@ module.exports = (function () { components: [ 'background-image', 'background-position', + 'background-size', 'background-repeat', 'background-attachment', 'background-color' @@ -626,6 +642,12 @@ module.exports = (function () { defaultValue: '0 0', shortestValue: '0' }, + 'background-size': { + canOverride: canOverride.always, + defaultValue: 'auto', + shortestValue: '0 0', + prefixShorthandValueWith: '/' + }, 'background-attachment': { canOverride: canOverride.always, defaultValue: 'scroll' diff --git a/lib/properties/validator.js b/lib/properties/validator.js index 71149e02..be77c363 100644 --- a/lib/properties/validator.js +++ b/lib/properties/validator.js @@ -1,6 +1,8 @@ // Validates various CSS property values +var Splitter = require('../text/splitter'); + module.exports = (function () { // Regexes used for stuff var widthKeywords = ['thin', 'thick', 'medium', 'inherit', 'initial']; @@ -21,6 +23,7 @@ module.exports = (function () { var backgroundRepeatKeywords = ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'inherit']; var backgroundAttachmentKeywords = ['inherit', 'scroll', 'fixed', 'local']; var backgroundPositionKeywords = ['center', 'top', 'bottom', 'left', 'right']; + var backgroundSizeKeywords = ['contain', 'cover']; var listStyleTypeKeywords = ['armenian', 'circle', 'cjk-ideographic', 'decimal', 'decimal-leading-zero', 'disc', 'georgian', 'hebrew', 'hiragana', 'hiragana-iroha', 'inherit', 'katakana', 'katakana-iroha', 'lower-alpha', 'lower-greek', 'lower-latin', 'lower-roman', 'none', 'square', 'upper-alpha', 'upper-latin', 'upper-roman']; var listStylePositionKeywords = ['inside', 'outside', 'inherit']; var outlineStyleKeywords = ['auto', 'inherit', 'hidden', 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset']; @@ -94,6 +97,16 @@ module.exports = (function () { return true; }, + isValidBackgroundSizePart: function(s) { + return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || validator.isValidVariable(s); + }, + isValidBackgroundPositionAndSize: function(s) { + if (s.indexOf('/') < 0) + return false; + + var twoParts = new Splitter('/').split(s); + return validator.isValidBackgroundSizePart(twoParts.pop()) && validator.isValidBackgroundPositionPart(twoParts.pop()); + }, isValidListStyleType: function (s) { return listStyleTypeKeywords.indexOf(s) >= 0 || validator.isValidVariable(s); }, diff --git a/test/data/issue-312-min.css b/test/data/issue-312-min.css index 7f63e0b3..cf91df93 100644 --- a/test/data/issue-312-min.css +++ b/test/data/issue-312-min.css @@ -1 +1 @@ -.envelope{background:url(one.png) top center repeat-x,url(one.png) bottom center repeat-x,url(two.png) 110% 10px no-repeat #eee;background-size:35px 4px,35px 4px,101px 61px} +.envelope{background:url(one.png) top center/35px 4px repeat-x,url(one.png) bottom center/35px 4px repeat-x,url(two.png) 110% 10px/101px 61px no-repeat #eee} diff --git a/test/unit-test.js b/test/unit-test.js index f885174d..bad994bf 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -1788,15 +1788,15 @@ title']{display:block}", }), 'shorthand properties': cssContext({ 'shorthand background #1' : [ - 'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll}', + 'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}', 'div{background:url(aaa) #111}' ], 'shorthand background #2' : [ - 'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}', + 'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto}', 'div{background:url(aaa) no-repeat #111}' ], 'shorthand important background' : [ - 'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important}', + 'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important}', 'div{background:url(aaa) #111!important}' ], 'shorthand border-width': [ @@ -1839,7 +1839,7 @@ title']{display:block}", 'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}' ], 'a background-image with a none and a linear-gradient should result in two shorthands' : [ - 'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll}', + 'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}', 'div{background:#111;background:linear-gradient(aaa) #111}' ] }), @@ -1922,7 +1922,7 @@ title']{display:block}", 'p{margin:1px;margin-right:2px!important;margin-left:4px!important}' ], 'should take into account important background-color and shorthand others into background': [ - 'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y}', + 'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}', 'p{background-color:#9fce00!important;background:url(hello) 1px 2px repeat-y}' ], 'should take into account important outline-color and default value of outline-width': [ @@ -1944,15 +1944,15 @@ title']{display:block}", 'p{margin:inherit}' ], 'merge multiple inherited background granular properties into one inherited shorthand': [ - 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit}', + 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit;;background-size:inherit}', 'p{background:inherit}' ], 'when shorter, optimize inherited/non-inherited background granular properties into an inherited shorthand and some non-inherited granular properties': [ - 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y}', + 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y;background-size:inherit}', 'p{background:inherit;background-repeat:repeat-y}' ], 'when shorter, optimize inherited/non-inherited background granular properties into a non-inherited shorthand and some inherited granular properties': [ - 'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y}', + 'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}', 'p{background:1px 2px repeat-y #9fce00;background-image:inherit}' ], 'put inherit to the place where it consumes the least space': [ @@ -2007,6 +2007,18 @@ title']{display:block}", '@-o-viewport': '@-o-viewport{width:device-width}', '@viewport': '@viewport{width:device-width}' }), + 'background size': cssContext({ + 'with background-position': 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}', + 'with background-position and spaces': [ + 'a{background:url(top.jpg) 50% 0 / auto 25% no-repeat}', + 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}' + ], + 'with background-position shorthands': 'a{background:url(top.jpg) 50px/25% no-repeat}', + 'with background-position shorthands and spaces': [ + 'a{background:url(top.jpg) 0 / cover no-repeat}', + 'a{background:url(top.jpg) 0/cover no-repeat}' + ] + }), 'misc advanced': cssContext({ 'outline auto': [ 'a{outline:5px auto -webkit-focus-ring-color}', -- 2.34.1