首页 > 解决方案 > Parsing CSS by javascript. Inconsistency across Edge and Chrome

问题描述

I am parsing with JS a CSS and I am trying to get the Unicode integer value of the "content" CSS rule but it's being handled differently across Edge and Chrome.

In Edge, the 'content' is a string of 7 chars:

enter image description here

In Chrome, it's a string of 3 chars:

enter image description here

csDef is my JS variable.

Here's how the CSS rule looks like:

enter image description here

Why is the value treated differently across the web-browses? And in JS, and how can I get the Unicode integer value correctly across these web-browsers?

EDIT:

Here's how I load the CSS rules:

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

            styleElement.textContent = styleContent;
            doc.body.appendChild(styleElement);

            return styleElement.sheet.cssRules;
        };

       var cssDefs =  Array.from(rulesForCssText(fileContent));

fileContent is the content of a file obtained by using a File object, I have an input type="file"and user selects the file from disk.

标签: javascriptcssgoogle-chromemicrosoft-edge

解决方案


免责声明:我没有明确的答案,但我从分析中学到了很多,我认为结果可能会引起其他人的兴趣。


首先,让我分享两个测试用例。基于 CSS 的重现了您描述的问题:

var d = document.implementation.createHTMLDocument("");
var s = document.createElement("style");
s.textContent = '.foo{content: "\\20ac";}';
d.body.appendChild(s);
var c = s.sheet.cssRules[0].style.getPropertyValue("content");
console.log("String '%s' has length %d", c, c.length);

桌面版 Firefox 和 Chrome 呈现数字字符引用 ( String '"€"' has length 3) 而 Edge 不呈现 ( String '"\20ac"' has length 7)。

有趣的是,第二个基于 HTML 的测试用例似乎没有表现出任何问题:

var s = document.getElementsByTagName("span")[0].textContent;
console.log("String '%s' has length %d", s, s.length);
<span>&#x20ac;</span>

两种浏览器都呈现实体 ( String '€' has length 1)。

那么,谁在这里?CSS Object Model ( CSSOM ) Editor's Draft说:

如果 property 是声明中 CSS 声明的属性名称的区分大小写匹配,则返回调用 序列化该声明的 CSS 值的结果。

……这就是我完全迷路的地方。

无论如何,我们谈论的是仍在积极开发中并且需要由不同供应商实现的复杂 Web API。无论是特定实现中的错误还是规范中的忽略(不太可能),这都是您的代码需要处理的问题。起点可以是:

function browserRendersCharacterReferences() {
  var d = document.implementation.createHTMLDocument("");
  var s = document.createElement("style");
  s.textContent = '.foo{content: "\\20ac";}';
  d.body.appendChild(s);
  return s.sheet.cssRules[0].style.getPropertyValue("content").length === 1;
}

function renderCharacterEntities(t) {
  // THIS FUNCTION IS WRONG, DON'T USE IT, IT'S JUST A QUICK EXAMPLE
  var r = /\\([\da-f]{4})\s?/gi;
  t = t.replace(r, function (match, codePoint) {
    return String.fromCharCode(parseInt(codePoint, 16));
  } );
  return t;
}

function rulesForCssText(css) {
  var d = document.implementation.createHTMLDocument("");
  var s = document.createElement("style");
  var c;
  s.textContent = css;
  d.body.appendChild(s);
  c = s.sheet.cssRules[0].style.getPropertyValue("content");
  if (!browserRendersCharacterReferences()) {
    c = renderCharacterEntities(c);
  }
  return c;
}

console.log(rulesForCssText('.foo{content: "\\20ac  and \\f102";}'));


PS我最初对此发表的一些评论\f102是完全错误的。这是一个完全有效的CSS 字符转义

转义以反斜杠开头,后跟表示字符的十六进制 Unicode 代码点值的十六进制数字。

… 映射到一个完全有效的 Unicode 字符,尽管它位于Private Use Area块中:

根据定义,Unicode 联盟不会分配字符的一系列代码点。[...] 故意将它们保留为未定义,以便第三方可以定义自己的字符,而不会与 Unicode 联盟分配冲突。

换句话说,它是为私人使用而保留的。有哪些用途?例如,您似乎正在使用的Ionicons 字体图标(将符号映射到未使用的 Unicode 位置的常规字体,因此它不会干扰常规文本):

<link href="https://unpkg.com/ionicons@4.2.2/dist/css/ionicons.min.css" rel="stylesheet">
<i class="icon ion-ios-add"></i>


推荐阅读