JavaScript的CSS解析器?

时间:2012-06-09 19:37:43

标签: javascript css parsing node.js

  

更新2018 :这个问题早在PostCSS存在之前就被问过了,我可能会使用它。

我想将一小块CSS解析为AST,这样我就可以为某些CSS指令添加前缀。

是否有用于JavaScript或Node的CSS解析器可以执行此操作?

我搜索过NPM。我发现的唯一有用的结果是parser-lib,但它是基于流的,看起来我需要为每个CSS节点编写自己的发射器。

更新:我还找到了JSCSSP,但它没有文档......

7 个答案:

答案 0 :(得分:10)

更新:我之前提到过JSCSSP,它似乎被放弃了。显然,NPM css module是最好的:

css = require 'css'

input = '''
  body {
    font-family: sans-serif;
  }
  #thing.foo p.bar {
    font-weight: bold;
  }
'''

obj = css.parse input
sheet = obj.stylesheet

for rule in sheet.rules
  rule.selectors = ('#XXX ' + s for s in rule.selectors)

console.log css.stringify(obj)

输出:

#XXX body {
  font-family: sans-serif;
}
#XXX #thing.foo p.bar {
  font-weight: bold;
}

答案 1 :(得分:5)

另外值得一提的是LESS。虽然它主要是CSS的一个(奇妙的)扩展,但LESS解析器确实允许您访问AST。

纯CSS样式表也是一个有效的LESS样式表,因此您可以从现有的内容开始,轻松进入LESS'扩展。

答案 2 :(得分:4)

对于它的价值,JSDOM使用CSSOM

答案 3 :(得分:4)

这是我们的开源CSS解析器css.js

这是一个简单的解析示例:

<script type="text/javascript">
    var cssString = ' .someSelector { margin:40px 10px; padding:5px}';
    //initialize parser object
    var parser = new cssjs();
    //parse css string
    var parsed = parser.parseCSS(cssString);

    console.log(parsed);
</script>

在编辑后将解析后的数据结构串行化为CSS字符串

var newCSSString = parser.getCSSForEditor(parsed);

我们的CSS解析器的主要功能是:

  • 轻巧。
  • 输出易于理解的javascript对象。没有复杂的AST。
  • 经过战斗测试(并经过单元测试)并且经常在我们的产品中使用(JotForm Form Designer)。
  • 它支持媒体查询,关键帧和字体规则。
  • 在解析时保留注释。

答案 4 :(得分:2)

修改

我最终使用的这个库足够轻便我的实现(在Kemal Dağ的回答中提供)。对于我所追求的客户端实现,其他选项太重了。

https://github.com/jotform/css.js

原创内容

a paid nerd原始答案很有效,直到我点击媒体查询。

我不得不添加一些递归,这就是我最终的结果。

请原谅我的TypeScript。

TypeScript Implementation

private scopeCSS(css: string): CSS.Stylesheet {
  let ast: CSS.Stylesheet = CSS.parse(css);
  let stylesheet: CSS.StyleRules|undefined = ast.stylesheet;
  if (stylesheet) {
    let rules: Array<CSS.Rule|CSS.Media> = stylesheet.rules;
    let prefix = `[data-id='sticky-container-${this.parent.id}']`;

    // Append our container scope to rules
    // Recursive rule appender
    let ruleAppend = (rules: Array<CSS.Rule|CSS.Media>) => {
      rules.forEach(rule => {
        let cssRule = <CSS.Rule>rule;
        let mediaRule = <CSS.Media>rule;
        if (cssRule.selectors !== undefined) {
          cssRule.selectors = cssRule.selectors.map(selector => `${prefix} ${selector}`);
        }
        if (mediaRule.rules !== undefined) {
          ruleAppend(mediaRule.rules);
        }
      });
    };

    ruleAppend(rules);
  }
  return ast;
}

Babel&#39; ized Vanilla JS Implementation

function scopeCSS(css, prefix) {
  var ast = CSS.parse(css);
  var stylesheet = ast.stylesheet;
  if (stylesheet) {
    var rules = stylesheet.rules;
    // Append our container scope to rules
    // Recursive rule appender
    var ruleAppend = function(rules) {
      rules.forEach(function(rule) {
        if (rule.selectors !== undefined) {
          rule.selectors = rule.selectors.map(function(selector) {
            return prefix + " " + selector;
          });
        }
        if (rule.rules !== undefined) {
          ruleAppend(rule.rules);
        }
      });
    };
    ruleAppend(rules);
  }
  return ast;
}

答案 5 :(得分:1)

答案 6 :(得分:0)

无需使用外部CSS解析器,我们可以使用本地CSS解析器

   
var sheetRef=document.getElementsByTagName("style")[0];

console.log("----------------list of  rules--------------");
for (var i=0; i<sheetRef.sheet.cssRules.length; i++){


var sheet = sheetRef.sheet ? sheetRef.sheet : sheetRef.styleSheet;


if (sheet.cssRules.length > 0) {
//console.log(sheet.cssRules[i]);
  console.log(sheet.cssRules[i].selectorText);
  console.log(sheet.cssRules[i].cssText);

                }}
.red{

color:red;
}

要插入规则

var sheetRef=document.getElementsByTagName("style")[0];
var sheet = sheetRef.sheet ? sheetRef.sheet : sheetRef.styleSheet;
sheet.insertRule('.foo{color:red;}', 0);

要删除规则 所有浏览器,版本9之前的IE除外

var sheetRef=document.getElementsByTagName("style")[0];
var sheet = sheetRef.sheet ? sheetRef.sheet : sheetRef.styleSheet;
sheet.removeRule (0);

要删除规则 所有浏览器,版本9之前的IE除外

var sheetRef=document.getElementsByTagName("style")[0];
var sheet = sheetRef.sheet ? sheetRef.sheet : sheetRef.styleSheet;
sheet.deleteRule (0);

添加媒体

  function AddScreenMedia () {
            var styleTag = document.getElementsByTagName("style")[0];

                // the style sheet in the style tag
            var sheet = styleTag.sheet ? styleTag.sheet : styleTag.styleSheet;

            if (sheet.cssRules) {   // all browsers, except IE before version 9
                var rule = sheet.cssRules[0];
                var mediaList = rule.media;

                alert ("The media types before adding the screen media type: " + mediaList.mediaText);
                mediaList.appendMedium ("screen");
                alert ("The media types after adding the screen media type: " + mediaList.mediaText);
            }
            else {  // Internet Explorer before version 9
                    // note: the rules collection does not contain the at-rules
                alert ("Your browser does not support this example!");
            }
        }
  @media print {
            body {
                font-size: 13px;
                color: #FF0000;
            }
          }
some text
<button onclick="AddScreenMedia ();">Add screen media</button>

获取规则

 
var sheetRef=document.getElementsByTagName("style")[0];

console.log("----------------list of  rules--------------");
for (var i=0; i<sheetRef.sheet.cssRules.length; i++){


var sheet = sheetRef.sheet ? sheetRef.sheet : sheetRef.styleSheet;


if (sheet.cssRules.length > 0) {
//console.log(sheet.cssRules[i]);
  console.log(sheet.cssRules[i].selectorText);
  console.log(sheet.cssRules[i].cssText);
  
  console.log(sheet.cssRules[i].style.color)
  console.log(sheet.cssRules[i].style.background)
    console.log(sheet.cssRules[i].style)

                }}
.red{

color:red;
background:orange;
}
<h1>red</h1>