Fixes #681 - property inheritance & restructuring.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 28 Sep 2015 08:43:31 +0000 (09:43 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 28 Sep 2015 09:46:56 +0000 (10:46 +0100)
We should not reorder CSS properties which are inherited and happen
to have a shorthand, which applies to `font`, `line-height` (which
shorthand is `font`), and `list-style`.

Other properties that don't have a shorthand are already not
reorderable based on their value.

History.md
lib/selectors/reorderable.js
test/fixtures/big-min.css
test/fixtures/blueprint-min.css
test/fixtures/bootstrap-min.css
test/selectors/reorderable-test.js
test/selectors/restructure-test.js

index 113e7b1..02d04dd 100644 (file)
@@ -6,6 +6,7 @@
 [3.4.5 / 2015-xx-xx](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.4...3.4)
 ==================
 
+* Fixed issue [#681](https://github.com/jakubpawlowicz/clean-css/issues/681) - property inheritance & restructuring.
 * Fixed issue [#675](https://github.com/jakubpawlowicz/clean-css/issues/675) - overriding with `!important`.
 
 [3.4.4 / 2015-09-21](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.3...v3.4.4)
index 97288b3..90bef4f 100644 (file)
@@ -46,7 +46,7 @@ function canReorderSingle(left, right) {
     return true;
   if (leftName != rightName && leftNameRoot == rightNameRoot && leftValue == rightValue)
     return true;
-  if (rightInSpecificSelector && leftInSpecificSelector && selectorsDoNotOverlap(rightSelector, leftSelector))
+  if (rightInSpecificSelector && leftInSpecificSelector && !inheritable(leftNameRoot) && !inheritable(rightNameRoot) && selectorsDoNotOverlap(rightSelector, leftSelector))
     return true;
 
   return false;
@@ -83,6 +83,12 @@ function selectorsDoNotOverlap(s1, s2) {
   return true;
 }
 
+function inheritable(name) {
+  // According to http://www.w3.org/TR/CSS21/propidx.html
+  // Others will be catched by other, preceeding rules
+  return name == 'font' || name == 'line-height' || name == 'list-style';
+}
+
 module.exports = {
   canReorder: canReorder,
   canReorderSingle: canReorderSingle
index c79b24d..c8bc893 100644 (file)
@@ -1,5 +1,4 @@
 /*! normalize.css 2012-01-31T16:06 UTC - http://github.com/necolas/normalize.css */
-small,sub,sup{font-size:75%}
 .bt_abo:hover,a{text-decoration:none}
 .bt_fonce a,.btn,.btn_abo,.btn_fonce,.btn_petit{filter:progid:dximagetransform.microsoft.gradient(enabled=false)}
 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
@@ -17,6 +16,7 @@ blockquote{margin:1em 40px}
 dfn{font-style:italic}
 mark{background:#ff0;color:#000}
 code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}
+small,sub,sup{font-size:75%}
 pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}
 q{quotes:none}
 q:after,q:before{content:'';content:none}
@@ -2275,7 +2275,6 @@ form .btn-rounded-degraded input[type=button],form .btn-rounded-degraded input[t
 #core-liberation .toolbox li.spacer span{display:block;width:1px;height:20px;margin-top:5px}
 #core-liberation .toolbox .txt-min,#core-liberation .toolbox .txt-plus{display:block;font-size:15px;padding-top:4px}
 #core-liberation .toolbox .txt-reset{display:block;font-family:"Times New Roman",Times,Georgia,serif;font-size:19px;padding:4px 0 0 3px}
-#page-mailfriend,#page-paywall{font-family:Verdana,sans-serif}
 .site-liberation .toolbox li a span{display:block}
 .site-liberation .toolbox li a.print span{margin-top:7px;width:16px;height:16px}
 .site-liberation .toolbox li a.favorite span{margin-top:5px;width:20px;height:18px}
@@ -2302,6 +2301,7 @@ form .btn-rounded-degraded input[type=button],form .btn-rounded-degraded input[t
 #core-liberation .sb-podcasts ul li a.itunes{background-position:-267px 0;width:50px}
 #core-liberation .sb-podcasts ul li a.xml{background-position:-322px 0;width:41px}
 #bar-liberation{display:block;position:fixed;top:0;left:0;z-index:10000;width:100%;height:40px;border-bottom:1px solid;font-family:Arial,Verdana,sans-serif;font-size:12px;line-height:14px}
+#page-mailfriend,#page-paywall{font-family:Verdana,sans-serif}
 body.init-bar-is-closed #bar-liberation{height:15px}
 #bar-liberation a,#bar-liberation a p{text-decoration:none;outline:0}
 #bar-liberation .content{position:relative;margin:auto;height:40px;width:1068px}
index a9cd7b7..71e99f0 100644 (file)
@@ -1,22 +1,23 @@
 h1 img,h2 img,h3 img,h4 img,h5 img,h6 img,html{margin:0}
+.pull-1,.pull-10,.pull-11,.pull-12,.pull-13,.pull-14,.pull-15,.pull-16,.pull-17,.pull-18,.pull-19,.pull-2,.pull-20,.pull-21,.pull-22,.pull-23,.pull-24,.pull-3,.pull-4,.pull-5,.pull-6,.pull-7,.pull-8,.pull-9,.push-1,.push-10,.push-11,.push-12,.push-13,.push-14,.push-15,.push-16,.push-17,.push-18,.push-19,.push-2,.push-20,.push-21,.push-22,.push-23,.push-24,.push-3,.push-4,.push-5,.push-6,.push-7,.push-8,.push-9{position:relative;float:left}
 .clear,hr{clear:both}
-html{padding:0;border:0;font-size:100.01%}
 a,abbr,acronym,address,article,aside,blockquote,body,caption,code,dd,del,dfn,dialog,div,dl,dt,em,fieldset,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,iframe,img,label,legend,li,nav,object,ol,p,pre,q,section,span,table,tbody,td,tfoot,th,thead,tr,ul{margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline}
-address,blockquote,dfn,em,tfoot{font-style:italic}
-h5,h6{font-size:1em;font-weight:700}
+address,blockquote,dfn,em{font-style:italic}
 article,aside,dialog,figure,footer,header,hgroup,nav,section{display:block}
-body{line-height:1.5;font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue",Arial,Helvetica,sans-serif}
 caption,td,th{text-align:left;font-weight:400;float:none!important}
 table,td,th{vertical-align:middle}
 blockquote:after,blockquote:before,q:after,q:before{content:''}
 blockquote,q{quotes:"" ""}
 a img{border:none}
 :focus{outline:0}
+html{padding:0;border:0;font-size:100.01%}
+body{line-height:1.5;font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue",Arial,Helvetica,sans-serif}
 h1,h2,h3,h4,h5,h6{font-weight:400;color:#111}
 h1{font-size:3em;line-height:1;margin-bottom:.5em}
 h2{font-size:2em;margin-bottom:.75em}
 h3{font-size:1.5em;line-height:1;margin-bottom:1em}
 h4{font-size:1.2em;line-height:1.25;margin-bottom:1.25em}
+h5,h6{font-size:1em;font-weight:700}
 h5{margin-bottom:1.5em}
 p{margin:0 0 1.5em}
 .left{float:left!important}
@@ -33,6 +34,7 @@ sub,sup{line-height:0}
 abbr,acronym{border-bottom:1px dotted #666}
 pre{margin:1.5em 0;white-space:pre}
 code,pre,tt{font:1em 'andale mono','lucida console',monospace;line-height:1.5}
+label,legend{font-weight:700}
 li ol,li ul{margin:0}
 ol,ul{margin:0 1.5em 1.5em 0;padding-left:1.5em}
 ul{list-style-type:disc}
@@ -42,6 +44,7 @@ table{border-collapse:separate;border-spacing:0;margin-bottom:1.4em;width:100%}
 thead th{background:#c3d9ff}
 caption,td,th{padding:4px 10px 4px 5px}
 tbody tr.even td,tbody tr:nth-child(even) td{background:#e5ecf9}
+tfoot{font-style:italic}
 caption{background:#eee}
 .small{font-size:.8em;margin-bottom:1.875em;line-height:1.875em}
 .large,legend{font-size:1.2em}
@@ -55,9 +58,7 @@ caption{background:#eee}
 .last{padding-right:0}
 .top{margin-top:0;padding-top:0}
 .bottom{margin-bottom:0;padding-bottom:0}
-label{font-weight:700}
 fieldset{padding:0 1.4em 1.4em;margin:0 0 1.5em;border:1px solid #ccc}
-legend{font-weight:700}
 #IE8#HACK,fieldset{padding-top:1.4em}
 #IE8#HACK,legend{margin-top:0;margin-bottom:0}
 input.text,input.title,input[type=password],input[type=text],textarea{background-color:#fff;border:1px solid #bbb}
@@ -204,7 +205,6 @@ input.span-24,textarea.span-24{width:938px}
 .pull-22{margin-left:-880px}
 .pull-23{margin-left:-920px}
 .pull-24{margin-left:-960px}
-.pull-1,.pull-10,.pull-11,.pull-12,.pull-13,.pull-14,.pull-15,.pull-16,.pull-17,.pull-18,.pull-19,.pull-2,.pull-20,.pull-21,.pull-22,.pull-23,.pull-24,.pull-3,.pull-4,.pull-5,.pull-6,.pull-7,.pull-8,.pull-9{float:left;position:relative}
 .push-1{margin:0 -40px 1.5em 40px}
 .push-2{margin:0 -80px 1.5em 80px}
 .push-3{margin:0 -120px 1.5em 120px}
@@ -230,7 +230,6 @@ input.span-24,textarea.span-24{width:938px}
 .push-23{margin:0 -920px 1.5em 920px}
 .push-24{margin:0 -960px 1.5em 960px}
 .append-bottom,.box,div.append-bottom{margin-bottom:1.5em}
-.push-1,.push-10,.push-11,.push-12,.push-13,.push-14,.push-15,.push-16,.push-17,.push-18,.push-19,.push-2,.push-20,.push-21,.push-22,.push-23,.push-24,.push-3,.push-4,.push-5,.push-6,.push-7,.push-8,.push-9{float:left;position:relative}
 .prepend-top,div.prepend-top{margin-top:1.5em}
 .box{padding:1.5em;background:#e5eCf9}
 hr{background:#ddd;color:#ddd;float:none;width:100%;height:1px;margin:0 0 1.45em;border:none}
index 84d5cf4..d19f3f9 100644 (file)
@@ -2,7 +2,7 @@ hr,img{border:0}
 body,figure{margin:0}
 .btn-group>.btn-group,.btn-toolbar .btn-group,.btn-toolbar .input-group,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.dropdown-menu{float:left}
 .navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}
-html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}
+html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
 article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}
 audio,canvas,progress,video{display:inline-block;vertical-align:baseline}
 audio:not([controls]){display:none;height:0}
@@ -316,6 +316,7 @@ select{background:#fff!important}
 .glyphicon-menu-down:before{content:"\e259"}
 .glyphicon-menu-up:before{content:"\e260"}
 *,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
+html{font-size:10px;-webkit-tap-highlight-color:transparent}
 body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}
 button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}
 a{color:#337ab7;text-decoration:none}
index 08bcc87..ea8fcb0 100644 (file)
@@ -241,6 +241,14 @@ vows.describe(canReorderSingle)
         assert.isTrue(result);
       }
     },
+    'different, non-overlapping simple selectors with inheritable property': {
+      'topic': function () {
+        return canReorderSingle(propertiesIn('a{font:inherit}')[0], propertiesIn('div{font-family:Helvetica}')[0]);
+      },
+      'must be false': function (result) {
+        assert.isFalse(result);
+      }
+    },
     'different, non-overlapping complex selectors': {
       'topic': function () {
         return canReorderSingle(propertiesIn('.one{border:none}')[0], propertiesIn('div{border:1px solid #f00}')[0]);
index 3a03602..48d1122 100644 (file)
@@ -4,10 +4,14 @@ var optimizerContext = require('../test-helper').optimizerContext;
 vows.describe('restructure')
   .addBatch(
     optimizerContext('advanced on', {
-      'up until changed': [
+      'up until changed #1': [
         'a{color:#000}div{color:red}.one{display:block}.two{display:inline;color:red}',
         'a{color:#000}.two,div{color:red}.one{display:block}.two{display:inline}'
       ],
+      'up until changed #2': [
+        'p{margin:0;font:inherit}h1{font-family:Helvetica;margin:20px}section h1{font-family:Helvetica;margin:40px}',
+        'p{margin:0;font:inherit}h1,section h1{font-family:Helvetica}h1{margin:20px}section h1{margin:40px}'
+      ],
       'up until top': [
         'a{width:75px}div{color:red}.one{display:block}.two{display:inline;color:red}',
         '.two,div{color:red}a{width:75px}.one{display:block}.two{display:inline}'