From 8cc801502f8d252a98d0ece2e2d6a34c428715c7 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sun, 16 Aug 2015 15:52:10 +0100 Subject: [PATCH] Fixes #645 - adds bottom to top `media` merging. In addition to top to bottom media merging we now support the reverse order one. It works similar way as same selector two-way merging - see 2f8f100592908225c853997051f56bb87c35c20d. Consider this example where top to bottom is not possible but reverse is: ```css @media (max-width:768px){.one{padding-right:0}} .one{padding:10px} @media (max-width:768px){.one{margin:0}} ``` --- History.md | 1 + lib/selectors/merge-media-queries.js | 39 +++++++++++++++------- test/fixtures/bootstrap-min.css | 15 ++++----- test/selectors/merge-media-queries-test.js | 24 ++++++++----- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/History.md b/History.md index 16f2eb1e..67a594d4 100644 --- a/History.md +++ b/History.md @@ -8,6 +8,7 @@ * Fixed issue [#612](https://github.com/jakubpawlowicz/clean-css/issues/612) - adds HTTP proxy support. * Fixed issue [#625](https://github.com/jakubpawlowicz/clean-css/issues/625) - adds length unit optimizations. * Fixed issue [#644](https://github.com/jakubpawlowicz/clean-css/issues/644) - adds time unit optimizations. +* Fixed issue [#645](https://github.com/jakubpawlowicz/clean-css/issues/645) - adds bottom to top `media` merging. * Fixed issue [#648](https://github.com/jakubpawlowicz/clean-css/issues/648) - adds property level at-rule support. [3.3.9 / 2015-08-09](https://github.com/jakubpawlowicz/clean-css/compare/v3.3.8...v3.3.9) diff --git a/lib/selectors/merge-media-queries.js b/lib/selectors/merge-media-queries.js index 89ea5720..0df0d6f5 100644 --- a/lib/selectors/merge-media-queries.js +++ b/lib/selectors/merge-media-queries.js @@ -24,22 +24,37 @@ function mergeMediaQueries(tokens) { positionLoop: for (var j = positions.length - 1; j > 0; j--) { - var source = tokens[positions[j]]; - var target = tokens[positions[j - 1]]; - var movedProperties = extractProperties(source); + var positionOne = positions[j]; + var tokenOne = tokens[positionOne]; + var positionTwo = positions[j - 1]; + var tokenTwo = tokens[positionTwo]; - for (var k = positions[j] + 1; k < positions[j - 1]; k++) { - var traversedProperties = extractProperties(tokens[k]); + directionLoop: + for (var direction = 1; direction >= -1; direction -= 2) { + var topToBottom = direction == 1; + var from = topToBottom ? positionOne + 1 : positionTwo - 1; + var to = topToBottom ? positionTwo : positionOne; + var delta = topToBottom ? 1 : -1; + var source = topToBottom ? tokenOne : tokenTwo; + var target = topToBottom ? tokenTwo : tokenOne; + var movedProperties = extractProperties(source); - // moved then traversed as we move @media towards the end - if (!canReorder(movedProperties, traversedProperties)) - continue positionLoop; - } + while (from != to) { + var traversedProperties = extractProperties(tokens[from]); + from += delta; + + if (!canReorder(movedProperties, traversedProperties)) + continue directionLoop; + } - target[2] = source[2].concat(target[2]); - source[2] = []; + target[2] = topToBottom ? + source[2].concat(target[2]) : + target[2].concat(source[2]); + source[2] = []; - reduced.push(target); + reduced.push(target); + continue positionLoop; + } } } diff --git a/test/fixtures/bootstrap-min.css b/test/fixtures/bootstrap-min.css index 19cb7509..1de385f4 100644 --- a/test/fixtures/bootstrap-min.css +++ b/test/fixtures/bootstrap-min.css @@ -387,6 +387,7 @@ dl{margin-bottom:20px} dd{margin-left:0} @media (min-width:768px){.dl-horizontal dt{float:left;width:10pc;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap} .dl-horizontal dd{margin-left:180px} +.container{width:750px} } abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777} .initialism{font-size:90%;text-transform:uppercase} @@ -410,8 +411,6 @@ pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;color:#333;word-b pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0} .container,.container-fluid{padding-right:15px;padding-left:15px} .pre-scrollable{overflow-y:scroll} -@media (min-width:768px){.container{width:750px} -} @media (min-width:992px){.container{width:970px} } @media (min-width:1200px){.container{width:1170px} @@ -739,13 +738,13 @@ select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-contro .form-inline .checkbox label,.form-inline .radio label{padding-left:0} .form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0} .form-inline .has-feedback .form-control-feedback{top:0} +.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right} } .form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0} .form-horizontal .checkbox,.form-horizontal .radio{min-height:27px} .form-horizontal .form-group{margin-right:-15px;margin-left:-15px} .form-horizontal .has-feedback .form-control-feedback{right:15px} -@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right} -.form-horizontal .form-group-lg .control-label{padding-top:14.33px} +@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px} .form-horizontal .form-group-sm .control-label{padding-top:6px} } .btn{display:inline-block;padding:6px 9pt;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;border-radius:4px} @@ -969,14 +968,13 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .navbar-form .checkbox label,.navbar-form .radio label{padding-left:0} .navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0} .navbar-form .has-feedback .form-control-feedback{top:0} +.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} } .breadcrumb>li,.pagination{display:inline-block} .btn .badge,.btn .label{top:-1px;position:relative} @media (max-width:767px){.navbar-form .form-group{margin-bottom:5px} .navbar-form .form-group:last-child{margin-bottom:0} } -@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} -} .navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0} .navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0} .navbar-btn{margin-top:8px;margin-bottom:8px} @@ -1398,6 +1396,7 @@ td.visible-lg,th.visible-lg{display:table-cell!important} .visible-lg-block{display:block!important} .visible-lg-inline{display:inline!important} .visible-lg-inline-block{display:inline-block!important} +.hidden-lg{display:none!important} } @media (max-width:767px){.hidden-xs{display:none!important} } @@ -1405,8 +1404,6 @@ td.visible-lg,th.visible-lg{display:table-cell!important} } @media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important} } -@media (min-width:1200px){.hidden-lg{display:none!important} -} .visible-print{display:none!important} @media print{.visible-print{display:block!important} table.visible-print{display:table} @@ -1422,4 +1419,4 @@ td.visible-print,th.visible-print{display:table-cell!important} .visible-print-inline-block{display:none!important} @media print{.visible-print-inline-block{display:inline-block!important} .hidden-print{display:none!important} -} \ No newline at end of file +} diff --git a/test/selectors/merge-media-queries-test.js b/test/selectors/merge-media-queries-test.js index f02c6b5e..6b92626d 100644 --- a/test/selectors/merge-media-queries-test.js +++ b/test/selectors/merge-media-queries-test.js @@ -37,24 +37,24 @@ vows.describe('merge media queries') '@media (min-width:1024px){body{width:100%}}@media screen{a{color:red}div{display:block}}' ], 'same two with breaking properties in between': [ - '@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}', - '@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}' + '@media screen{a{color:red}}.one{color:#00f;display:inline}@media screen{div{display:block}}', + '@media screen{a{color:red}}.one{color:#00f;display:inline}@media screen{div{display:block}}' ], 'same two with breaking @media in between': [ - '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}', - '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}' + '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f;display:inline}}@media screen{div{display:block}}', + '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f;display:inline}}@media screen{div{display:block}}' ], 'same two with breaking nested @media in between': [ - '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}', - '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}' + '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f;display:inline}}}@media screen{div{display:block}}', + '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f;display:inline}}}@media screen{div{display:block}}' ], 'intermixed': [ '@media screen{a{color:red}}@media (min-width:1024px){p{width:100%}}@media screen{div{display:block}}@media (min-width:1024px){body{height:100%}}', '@media screen{a{color:red}div{display:block}}@media (min-width:1024px){p{width:100%}body{height:100%}}' ], 'same two with overriding shorthand in between': [ - '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:13px Helvetica}}@media screen{div{display:block}}', - '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:13px Helvetica}}@media screen{div{display:block}}' + '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:13px Helvetica;display:inline}}@media screen{div{display:block}}', + '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:13px Helvetica;display:inline}}@media screen{div{display:block}}' ], 'same two with different component property in between': [ '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font-weight:700}}@media screen{div{display:block}}', @@ -71,6 +71,14 @@ vows.describe('merge media queries') 'with comments': [ '@media screen{a{color:red}}/*! a comment */@media screen{a{display:block}}', '/*! a comment */@media screen{a{color:red;display:block}}' + ], + 'backwards': [ + '@media (max-width:768px){.one{padding-right:0}}.one{padding:10px}@media (max-width:768px){.one{margin:0}}', + '@media (max-width:768px){.one{padding-right:0;margin:0}}.one{padding:10px}' + ], + 'backward of two with overriding shorthand in between': [ + '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:13px Helvetica}}@media screen{div{display:block}}', + '@media screen{a{font-size:10px}div{display:block}}@media (min-width:1024px){.one{font:13px Helvetica}}' ] }) ) -- 2.34.1