如何为SVG元素创建样式表?

时间:2014-07-23 20:18:59

标签: javascript dom svg stylesheet

我尝试将样式表添加到SVG元素,如下所示:

var theSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var theStyle = document.createElementNS("http://www.w3.org/2000/svg", "style");
theSvg.appendChild(theStyle);
console.log("theStyle.sheet=", theStyle.sheet); // undefined, try adding svg to DOM
document.body.appendChild(theSvg);
console.log("theStyle.sheet=", theStyle.sheet); // still undefined

我应该怎样做才能到达theStyle中的工作表节点?

这里有一个小提琴:http://jsfiddle.net/XaV7D/2/

3 个答案:

答案 0 :(得分:2)

正如@RobertLongson在评论中指出的那样,问题在于SVG specs define a svg:style element interface,但它并没有实现the CSS OM interfaces associated with a stylesheet's owner element

以下是一些解决方法(在等待SVG 2规范实现最新的CSS OM规范时):

  1. 使用(X)HTML样式元素。如果您的SVG代码在(X)HTML文档中内联,则可以使用HTML <style>元素来设置SVG的样式。只需确保在默认命名空间中创建样式元素或在XHTML命名空间中显式创建它,以便获得HTMLStyleElement的实例,而不是SVGStyleElement

    将新创建的HTMLStyleElement添加到文档的头部,并为您创建CSS样式表对象:

    var hs = document.createElement("style");
    hs.type = "text/css";
    document.head.insertBefore(hs, null);
    hs.sheet.insertRule("circle{fill:red;}", 0); 
    

    This answer goes into more detail about dynamically creating stylesheets in HTML, including a working example.

  2. (理论上) 使用xml-stylesheet processing instruction。如果您的SVG代码位于独立的SVG文件中,则可以使用XML处理指令链接外部样式表。处理指令节点提供对样式表对象的访问。

    但是,与<style>元素(可以为空)不同,处理指令节点必须链接到文件,否则浏览器将永远不会初始化样式表对象。我试图通过将外部文件定义为正确MIME类型的空数据URI来解决这个问题。 从控制台运行时,通常(但不一致)在FF / Chrome中运行,但不是从嵌入式脚本运行。在Chrome中,sheet属性始终为null,与Chrome相同处理跨域样式表; Firefox提供了明确的安全错误。我认为它在IE中根本不起作用,它不像非图像数据URI文件。

    var xs = document.createProcessingInstruction(
        "xml-stylesheet", 
        "href='data:text/css,' type='text/css'");
    document.insertBefore(xs, document.rootElement);
    xs.sheet.insertRule("circle{fill:blue;}", 0); 
    

    您并不清楚为什么您试图动态创建样式表。如果目的是实际链接到同域服务器上的有效样式表,那么安全问题就不是问题;问题是数据URI被视为跨源。

  3. 使用svg:style元素,然后使用document.styleSheets访问样式表对象(从评论到其他答案,似乎这就是您已经在做的事情)。遍历所有样式表,直到找到将样式元素作为所有者节点的样式表:

    var ss = document.createElementNS("http://www.w3.org/2000/svg", "style");
    svgElement.appendChild(ss);
    var sheets = document.styleSheets,
        sheet;
    for(var i=0, length=sheets.length; i<length; i++){
       sheet=sheets.item(i);
       if (sheet.ownerNode == ss) break;
    }
    sheet.insertRule("circle{fill:green;}", 0);
    

    无论您的SVG是否在独立文件中,这都应该有效。

答案 1 :(得分:0)

您可以在style元素中使用svg个节点。

来自MDN的示例:

<svg width="100%" height="100%" viewBox="0 0 100 100"
     xmlns="http://www.w3.org/2000/svg">
  <style>
    /* <![CDATA[ */
    circle {
      fill: orange;
      stroke: black;
      stroke-width: 10px;
    }
    /* ]]> */
  </style>

  <circle cx="50" cy="50" r="40" />
</svg>

您可以像在HTML中一样追加它们。

var style = document.createElement('style');
style.setAttribute("type", "text/css");
var svg = document.getElementsByTagName("svg")[0];
svg.appendChild(style);

答案 2 :(得分:0)

IE11的SVGStyleElements中缺少“工作表”属性
根据AmeliaBR的回答,我做了一个polyfill:

if (!('sheet' in SVGStyleElement.prototype)) {
    Object.defineProperty(SVGStyleElement.prototype, 'sheet', {
        get:function(){
            var all = document.styleSheets;
            for (var i=0, sheet; sheet=all[i++];) {
                if (sheet.ownerNode === this) return sheet;
            }

        }
    });
}