在 JavaScript / jQuery 中解析 CSS

IT技术 javascript jquery css parsing
2021-02-11 20:00:41

我正在尝试在 JavaScript 中实现 CSS 的解析,以便:

a {
  color: red;
}

被解析为对象:

{
  'a' {
    'color': 'red'
  }
}

首先,我可以使用JavaScript / jQuery吗?

我的实现非常基础,所以我确信它无论如何都不是万无一失的。例如,它适用于基本 CSS,但适用于以下类型的属性:

background: url(data:image/png;base64, ....);

它失败了,因为我正在使用split(';')分隔property:value对。在这里,;发生在 中value,所以它也在那个点分裂。

有没有其他方法可以做到这一点?

这是代码:

parseCSS: function(css) {
    var rules = {};
    css = this.removeComments(css);
    var blocks = css.split('}');
    blocks.pop();
    var len = blocks.length;
    for (var i = 0; i < len; i++)
    {
        var pair = blocks[i].split('{');
        rules[$.trim(pair[0])] = this.parseCSSBlock(pair[1]);
    }
    return rules;
},

parseCSSBlock: function(css) { 
    var rule = {};
    var declarations = css.split(';');
    declarations.pop();
    var len = declarations.length;
    for (var i = 0; i < len; i++)
    {
        var loc = declarations[i].indexOf(':');
        var property = $.trim(declarations[i].substring(0, loc));
        var value = $.trim(declarations[i].substring(loc + 1));

        if (property != "" && value != "")
            rule[property] = value;
    }
    return rule;
},

removeComments: function(css) {
    return css.replace(/\/\*(\r|\n|.)*\*\//g,"");
}

谢谢!

4个回答

您可以轻松地使用浏览器自带的 CSSOM 来解析 CSS:

var rulesForCssText = function (styleContent) {
    var doc = document.implementation.createHTMLDocument(""),
        styleElement = document.createElement("style");

   styleElement.textContent = styleContent;
    // the style will only be parsed once it is added to a document
    doc.body.appendChild(styleElement);

    return styleElement.sheet.cssRules;
};

对于返回的每个规则,您可以查看 中的属性rule.style有关示例,请参见http://jsfiddle.net/v2JsZ/

有一个缺点,浏览器特定的规则丢失了
2021-03-14 20:00:41
你摇滚!它就像一个魅力!:) 我想它是在浏览器中实现的最佳选择。我认为你不需要任何图书馆,而且它比任何图书馆都快。
2021-03-28 20:00:41
我已经用一个只解析 css 的例子更新了你的 jsfiddle:jsfiddle.net/v2JsZ/85
2021-04-03 20:00:41
使用这种方法有什么缺点吗?如果这有效,我想知道使用任何 JS 库来完成这样一项非平凡的任务有什么意义
2021-04-07 20:00:41
@DonBox:好吧,正如我所说:为了使用浏览器 CSSOM,样式表必须是现有文档的一部分。这意味着最终用户将看到样式作为他们正在查看的页面的一部分。对于某些情况,这不太理想。IE 不能使用这种技术来处理与当前用户正在查看的内容没有直接关系的抽象样式表。
2021-04-11 20:00:41

有一个用 Javascript 编写的 CSS 解析器,称为JSCSSP

@ankit:那你要什么?如果你想正确解析(意味着你可以处理任意的 CSS),那么你最终会得到一个“重”的库。否则,您可以坚持使用轻量级实现,因为它很容易被破坏。
2021-03-15 20:00:41
@josh3736 看起来您的评论是我需要的推动力。我很担心性能问题,但结果证明它运行得很好!
2021-03-21 20:00:41
我之前确实看过它,但不想使用它,因为它太重了它做了很多我不需要做的事情
2021-03-25 20:00:41
我找不到使用 JSCSSP 从 JSON 对象解析回 CSS 的方法。JSCSSP 将 CSS 解析为 JSON 很棒,它使用的结构正是我们所需要的,但我们还需要一种将 JSON 对象解析回 CSS 的方法。任何想法/建议?
2021-03-26 20:00:41
不要使用那个解析器,我用“Bootstrap v3.3.2”的压缩源进行了测试,解析器只返回了25条规则。
2021-04-02 20:00:41

要编写最简单的解析器,请遵循规范中定义的标记化和 CSS语法的确切规则请注意,您不必通过墨水实现规范。您可以从最有可能遇到的小部件和 CSS 开始,然后从那里扩展。更好的是,除非这是一个学习练习,否则完全跳过整个过程并使用@Matthew 的解决方案。

有多种可用于 JavaScript 的词法扫描器和解析器生成器。整个语法可在 w3 的网站上找到。当您可以简单地使用它和解析器生成器在 JavaScript 中生成解析器时,为什么还要重新工作。

  1. 吉森
  2. peg.js
  3. Cruiser.Parse
  4. 麦克莱克瑟
  5. JS/CC

CSS 的产生规则如下。

stylesheet
  : [ CHARSET_SYM STRING ';' ]?
    [S|CDO|CDC]* [ import [ CDO S* | CDC S* ]* ]*
    [ [ ruleset | media | page ] [ CDO S* | CDC S* ]* ]*
  ;
import
  : IMPORT_SYM S*
    [STRING|URI] S* media_list? ';' S*
  ;
media
  : MEDIA_SYM S* media_list LBRACE S* ruleset* '}' S*
  ;
media_list
  : medium [ COMMA S* medium]*
  ;
medium
  : IDENT S*
  ;
page
  : PAGE_SYM S* pseudo_page?
    '{' S* declaration? [ ';' S* declaration? ]* '}' S*
  ;
pseudo_page
  : ':' IDENT S*
  ;
operator
  : '/' S* | ',' S*
  ;
combinator
  : '+' S*
  | '>' S*
  ;
unary_operator
  : '-' | '+'
  ;
property
  : IDENT S*
  ;
ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration? [ ';' S* declaration? ]* '}' S*
  ;
selector
  : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
  ;
simple_selector
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;
class
  : '.' IDENT
  ;
element_name
  : IDENT | '*'
  ;
attrib
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ]? ']'
  ;
pseudo
  : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
  ;
declaration
  : property ':' S* expr prio?
  ;
prio
  : IMPORTANT_SYM S*
  ;
expr
  : term [ operator? term ]*
  ;
term
  : unary_operator?
    [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
      TIME S* | FREQ S* ]
  | STRING S* | IDENT S* | URI S* | hexcolor | function
  ;
function
  : FUNCTION S* expr ')' S*
  ;
/*
 * There is a constraint on the color that it must
 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
 * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
 */
hexcolor
  : HASH S*
  ;
您可以查看 CoffeeScript 以获得一个很好的文档化示例:jashkenas.github.com/coffee-script/documentation/docs/...
2021-03-17 20:00:41
这些生成规则对于 CSS3 来说已经过时了。例如,我没有看到“~”
2021-04-09 20:00:41
如果有人遇到这个问题,正如@huyz 所提到的,这个答案不仅会过时(不是 OP 的错),而且在这个阶段,CSS 解析(不幸的是)比任何人真正意识到的都要复杂。
2021-04-11 20:00:41

简单的例子,没有经过测试但应该可以工作,我在我的项目中使用了类似的。

var div = jQuery('<div/>');
div[0].style = 'position:absolute;left:5px;top:10px;'; //Css to parse

div.css('left'); // => '5px'
div.css('top'); // => '10px'
div[0].style; // => Object containing all css