具有公共属性的

时间:2015-05-29 01:54:21

标签: javascript jquery html css optimization

此脚本包含在包含任何声明样式(不包括style=""设置的样式)的HTML文档中时,将向页面输出优化的样式表。该脚本使用以下方法...

  1. 忽略所有@:规则,按原样保留自适应样式。
  2. 将规则分成单个选择器规则,以便我们稍后可以测试继承。
  3. 删除适用于文档中不存在的选择器的规则,这要归功于@RickHitchcock
  4. 以相同的格式(不包括百分比)检索声明的和计算的样式,然后相互比较两个值,然后删除属性并再次检查。
  5. 如果声明的值与计算值匹配,并通过删除值更改的属性,则设置保持标志。这告诉我们该属性是否对元素有影响,如果没有元素受到属性的影响...将其删除。
  6. 如果剩余的CSSRule中没有属性,则删除该规则。
  7. 作为副作用,大多数不会更改浏览器默认设置的选择器都将被删除(除非使用font而不是font-*和类似的选项将激活其余的设置那个属性)。
  8. 在包含与动态元素相关的样式的网站上运行此脚本时,我只是将它们包装在媒体查询中

    @media (min-width: 0px) {
        /* This says that these styles always apply */
    }
    

    问题

    如何将具有共同属性的选择器分组?

    Demo

    var stylesheets = document.styleSheets, stylesheet, i;
    var ruleText = "";
    if(stylesheets && stylesheets.length) {
        for (i = 0; (stylesheet = stylesheets[i]); i++) {
            var rules = stylesheet.rules, rule, j;
            if(rules && rules.length) {
                for (j = 0; (rule = rules[j]); j++) {
                    if(rule.type === rule.STYLE_RULE) {
                        if(rule.selectorText.indexOf(',') >= 0) {
                            var newRules = [];
                            var selectors = rule.selectorText.split(','), selector, k;
                            for(k = 0; (selector = selectors[k]); k++) {
                                var styles = rule.style, style, l;
                                var elements = document.querySelectorAll(selector.trim()), element, l;
                                if(elements.length) {
                                    var styleString = '';
                                    for(m = 0; (style = styles[m]); m++) {
                                        styleString += style + ': ' + styles.getPropertyValue(style) + "; ";
                                    }
                                    newRules.push((selector.trim() + ' { ' + styleString.trim() + ' }'));
                                }
                            }
                            stylesheet.deleteRule(j);
                            for(k = 0; (rule = newRules[k]); k++) {
                                stylesheet.insertRule(rule, j);
                            }
                        }
                    }
                }
                for (j = 0; (rule = rules[j]); j++) {
                    if(rule.type === rule.STYLE_RULE && rule.selectorText.indexOf(':') < 0) {
                        var styles = rule.style, style, k;
                        var elements = document.querySelectorAll(rule.selectorText);
                        if(elements && elements.length) {
                            for(k = 0; (style = styles[k]); k++) {
                                var value = styles.getPropertyValue(style);
                                if(value.indexOf('%') < 0) {
                                    var elements = document.querySelectorAll(rule.selectorText), element, m;
                                    var keep = false;
                                    for(m = 0; (element = elements[m]); m++) {
                                        var computed = window.getComputedStyle(element).getPropertyValue(style);
                                        var match1 = value === computed;
                                        styles.removeProperty(style);
                                        var computed = window.getComputedStyle(element).getPropertyValue(style);
                                        var match2 = value === computed;
                                        styles.setProperty(style, value);
                                        if( match1 && !match2 ) {
                                            keep = true;
                                        }
                                    }
                                    if(!keep) {
                                        styles.removeProperty(style);
                                    }
                                }
                            }
                            ruleText += rule.cssText + "\n";
                        }
                    } else {
                        ruleText += rule.cssText + "\n";
                    }
                }
            }
        }
    }
    document.body.innerHTML = '<pre>' + ruleText + '<pre>';
    

    未来观众:这在github上以optiCSS的形式提供(阅读:令人愉悦)

1 个答案:

答案 0 :(得分:1)

这看起来很棒,我只有一个小建议。

按如下方式更改您的代码:

for (j = 0; rule = rules[j]; j++) {
  var styles = rule.style, style, k;
  var elements = document.querySelectorAll(rule.selectorText);

  if(elements.length) {
    for(k = 0; style = styles[k]; k++) {
      ...
    }
    console.log(rule.cssText);
  }
}

这将阻止输出没有任何匹配HTML的规则。

this Fiddle 中,li规则与您的代码一起输出,但不会通过上述修改输出。

下一个挑战是简化fontborderpadding,......样式。

<小时/> 根据编辑#25 ,您将看到一个如下字符串:

html { margin-right: 0px; margin-left: 0px; height: 100%; }
body { margin-right: 0px; margin-left: 0px; height: 100%; margin-top: 0px; }
body { margin-bottom: 5px; background-color: rgb(255, 0, 0); }
@media (max-width: 500px) { 
  body { background: blue; }
}

以下是如何将其变为:

html {margin-right:0px;margin-left:0px;height:100%;}
body {margin-right:0px;margin-left:0px;height:100%;margin-top:0px;margin-bottom:5px;background-color:rgb(255 0 0);}
@media (max-width: 500px) { 
  body { background: blue; }
}

在此过程中,您将获得两个对象:

html {"margin-right":"0px;","margin-left":"0px;","height":"100%;"}
body {"margin-right":"0px;","margin-left":"0px;","height":"100%;","margin-top":"0px;","margin-bottom":"5px;","background-color":"rgb(255, 0, 0);"}

首先,将您的媒体查询输出分开,因为您不希望它受到影响:

var ruleText = "", mediaText = "";
...
        if (styles.length) {
            ruleText += rule.cssText + "\n";
        }
    } else {
        mediaText += rule.cssText + "\n";
    }

然后在循环之后放置它:

var inp= ruleText.split('\n'),
    out= '',
    selectors= {};

inp.forEach(function(val) {
  if(val) {
    var selector= val.split(/ *{/)[0],
        styles= val.split(/{ */)[1].split('}')[0].split(/; */);

    selectors[selector]= selectors[selector] || {};
    styles.forEach(function(val) {
      if(val) {
        var st= val.split(/ *: */);
        selectors[selector][st[0]]= st[1]+';';
      }
    });
  }
});

for(var i in selectors) {
  out+= i+' '+JSON.stringify(selectors[i]).replace(/[,"]/g,'')+'\n';
}
document.body.innerHTML= '<pre>'+out+mediaText+'</pre>';

为简单起见,上面的代码假设CSS中没有包含双引号,分号,逗号或花括号的字符串内容。这会使事情变得复杂。

Fiddle