javascript - 具有通用属性的 CSSRules 组选择器

标签 javascript jquery html css optimization

此脚本包含在包含任何已声明样式(不包括由 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>';

future 的观众:这在 github 上可用 optiCSS (读:赏心悦目)

最佳答案

这看起来不错,我只有一个小建议。

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

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

关于javascript - 具有通用属性的 CSSRules 组选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30519899/

相关文章:

javascript - Ember - 绑定(bind)嵌套数组

javascript - 为什么我的无限轮播代码会破坏我的网页?

javascript - 如何使用 Javascript/jQuery 将事件处理程序绑定(bind)到删除数组项?

javascript - 使用 jQuery 和逻辑流程语句更改背景图像

javascript - 如何使用更严格的限制自定义 `&lt;input&gt;` 元素

java - 将neo4j数据集连接到Web应用程序的最简单方法是?

javascript - 我可以将状态属性设置为回调吗?

javascript - jquery window.scroll 函数内的变量范围问题

jQuery 滚动以在 div 上同时淡入淡出和动画

python - 在Python中使用Selenium选择子元素