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

Javascript 如何为SVG元素创建样式表?,javascript,dom,svg,stylesheet,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.she

我尝试向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
我应该怎么做才能到达样式中的图纸节点


这里有一把小提琴:

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

来自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>

正如@RobertLongson在评论中指出的那样,问题在于,它没有实现

以下是一些变通方法(在等待SVG2规范实现最新的CSS OM规范时):

  • 使用(X)HTML样式元素。如果SVG代码内嵌在(X)HTML文档中,则可以使用HTML
    元素来设置SVG的样式。只需确保在默认名称空间中创建样式元素,或者在XHTML名称空间中显式创建样式元素,以便获得的是而不是
    SVGStyleElement
    的实例

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

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

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

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

  • 使用
    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);
    
    var ss=document.createElements(“http://www.w3.org/2000/svg“,”风格“);
    附肢儿童(ss);
    var sheets=document.styleSheets,
    床单;
    对于(var i=0,length=sheets.length;iIE11中的SVGStyleElements中缺少“sheet”属性
    根据AmeliaBR的回答,我做了一个polyfill:

    if(!('sheet'在SVGStyleElement.prototype中)){
    Object.defineProperty(SVGStyleElement.prototype,“sheet”{
    get:function(){
    var all=document.styleSheets;
    对于(变量i=0,工作表;工作表=all[i++];){
    如果(sheet.ownerNode==此)返回工作表;
    }
    }
    });
    }
    
    谢谢Jonathan,我知道。但我想从javascript创建它们。请看我的问题!再次感谢Jonathan,但我在我的示例中做到了。我想做的是访问工作表(通常是样式元素的属性)。但是我不能。然后我不能操作工作表。(我可以,但不是我想要的方式!)从来没有听说过
    sheet
    属性tbh,你的意思是
    document.styleSheets
    ?你可以像这样通过textContent属性访问样式描述。theStyle.textContent=“svg{background color:blue;}”@Jonathan,它是一样的,但是
    sheet
    是来自
    style
    元素的链接。当它起作用时;-)请通过联系w3c svg工作组,并要求他们将其添加到SVG2规范中。谢谢,@RobertLongson。完成。下面是导致规范编辑操作的线程:。我刚刚推送了将LinkStyle(又称图纸访问器)添加到SVGStyleElement的更新。要在Blink(Opera/Chrome)中跟踪此功能的实现,请参阅。@ErikDahlström很高兴看到许多peeople人在合作!谢谢AmeliaBR,这是对当前状态的一个很好的解释。(实际上我现在只添加文本节点。insertRule的优点是您可以稍后删除该规则,但为了避免这种情况,我重新设计了一些东西。)您也可以执行
    ss.innerHTML=“circle{fill:green;}”
    @CharlesL。这在大多数现代浏览器中都应该适用,但要注意,SVG命名空间元素不支持
    innerHTML
    属性。但是,您可以使用
    ss.textContent
    达到相同的效果,因为您无论如何都不会解析HTML元素。
    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);