How do I create a style sheet for an SVG element?

2019-08-07 10:40发布

I tried to add a style sheet to an SVG element, like this:

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

What am I supposed to do to get to the sheet node there in theStyle?

There is a fiddle here: http://jsfiddle.net/XaV7D/2/

2条回答
小情绪 Triste *
2楼-- · 2019-08-07 11:04

You can use style nodes inside the svg element.

Example from 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>

You can just append them like you would do in HTML.

var style = document.createElement('style');
style.setAttribute("type", "text/css");
var svg = document.getElementsByTagName("svg")[0];
svg.appendChild(style);
查看更多
叼着烟拽天下
3楼-- · 2019-08-07 11:13

As @RobertLongson points out in the comments, the problem is that the SVG specs define a svg:style element interface, but it doesn't implement the CSS OM interfaces associated with a stylesheet's owner element.

Here are a couple work-around approaches (while waiting for the SVG 2 specs to implement the latest CSS OM specs):

  1. Use an (X)HTML style element. If your SVG code is inline within an (X)HTML document, then the HTML <style> element can be used to style the SVG. Just make sure that you either create the style element in the default namespace or explicitly create it in the XHTML namespace, so that you get an instance of HTMLStyleElement, not SVGStyleElement.

    Add the newly-created HTMLStyleElement to the head of your document, and the CSS stylesheet object will be created for you:

    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. (Theoretically) Use an xml-stylesheet processing instruction. If your SVG code is in a stand-alone SVG file, then you can use XML processing instructions to link external stylesheets. The processing instruction node provides access to the stylesheet object.

    However, unlike a <style> element, which can be empty, the processing instruction node must link to a file, or the browser will never initialize the stylesheet object. I tried to get around that by defining the external file as an empty data URI of the correct MIME type. It usually, but not consistently, works in FF/Chrome when run from the console, but not from an embedded script. In Chrome, the sheet property is always null, the same way Chrome treats cross-domain stylesheets; Firefox gives an explicit security error. I assume it won't work at all in IE, which doesn't like non-image data URI files.

    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); 
    

    You weren't clear about why you were trying to dynamically create a style sheet. If the intent is to actually link to a valid stylesheet on a same-domain server, then the security problems wouldn't be an issue; the problem is that data URIs are treated as cross-origin.

  3. Use a svg:style element, but then access the stylesheet object using document.styleSheets (from the comments to the other answer, it seems this is what you're already doing). Cycle through all the stylesheets until you find the one that has your style element as the owner node:

    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);
    

    This should work regardless of whether or not your SVG is in a stand-alone file.

查看更多
登录 后发表回答