【问题标题】:CSSRules group selectors with common properties具有公共属性的 CSSRules 组选择器
【发布时间】:2015-08-11 17:58:13
【问题描述】:

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

  1. 忽略任何 @: 规则以保持响应式样式不变。
  2. 将规则分成单个选择器规则,以便我们稍后测试继承。
  3. 删除适用于文档中不存在的选择器的规则,感谢 @RickHitchcock 的贡献。
  4. 以相同的格式(不包括百分比)检索声明的样式和计算的样式,然后相互比较两个值,然后删除属性并再次检查。
  5. 如果声明的值与计算的值匹配并且通过删除属性值发生变化,则设置保持标志。这告诉我们该属性是否对元素有影响,如果没有元素受到该属性的影响...删除它。
  6. 如果剩余的CSSRule 中没有属性,则删除该规则。
  7. 作为副作用,大多数不更改浏览器默认设置的选择器将被删除(除非使用 font 而不是 font-* 和类似的,这将激活该属性的其余设置)。李>

在包含与动态元素相关的样式的网站上运行此脚本时,我只是将它们包装在媒体查询中

@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 的形式获得(阅读:令人赏心悦目)

【问题讨论】:

标签: javascript jquery html css optimization


【解决方案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,……样式。


根据您的Edit #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

【讨论】:

  • 感谢您有 CSS 文件需要清理。我花了很多时间清理旧的 Word-to-HTML 和 Dreamweaver 文件,这些文件充满了内联 CSS。
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
  • 2017-03-13
相关资源
最近更新 更多