117

When an SVG is directly included in a document using the <svg> tag, you can apply CSS styles to the SVG via the document's stylesheet. However, I am trying to apply a style to an SVG which is embedded (using the <object> tag).

Is it possible to use anything such as the following code?

object svg { 
    fill: #fff; 
}
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
Joshua Sortino
  • 2,317
  • 4
  • 18
  • 13
  • 1
    I came up with a lightweight way to do this which would work great for what you are trying to do. See this Q&A: http://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement/ – Drew Baker Aug 16 '12 at 00:16
  • Here's [an answer](https://stackoverflow.com/a/39663457/1717535) that actually gets the job done (from *[Manipulating external svg file style properties with CSS](https://stackoverflow.com/questions/22252409/manipulating-external-svg-file-style-properties-with-css)*.) – Fabien Snauwaert May 06 '19 at 15:06

6 Answers6

119

Short answer: no, since styles don't apply across document boundaries.

However, since you have an <object> tag you can insert the stylesheet into the svg document using script.

Something like this, and note that this code assumes that the <object> has loaded fully:

var svgDoc = yourObjectElement.contentDocument;
var styleElement = svgDoc.createElementNS("http://www.w3.org/2000/svg", "style");
styleElement.textContent = "svg { fill: #fff }"; // add whatever you need here
svgDoc.getElementById("where-to-insert").appendChild(styleElement);

It's also possible to insert a <link> element to reference an external stylesheet:

var svgDoc = yourObjectElement.contentDocument;
var linkElm = svgDoc.createElementNS("http://www.w3.org/1999/xhtml", "link");
linkElm.setAttribute("href", "my-style.css");
linkElm.setAttribute("type", "text/css");
linkElm.setAttribute("rel", "stylesheet");
svgDoc.getElementById("where-to-insert").appendChild(linkElm);

Yet another option is to use the first method, to insert a style element, and then add an @import rule, e.g styleElement.textContent = "@import url(my-style.css)".

Of course you can directly link to the stylesheet from the svg file too, without doing any scripting. Either of the following should work:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="my-style.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg">
  ... rest of document here ...
</svg>

or:

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <link href="my-style.css" type="text/css" rel="stylesheet" 
          xmlns="http://www.w3.org/1999/xhtml"/>
  </defs>
  ... rest of document here ...
</svg>

Update 2015: you can use jquery-svg plugin for apply js scripts and css styles to an embedded SVG.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124
Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • Is this a method to link an external stylesheet? If not, is that possible? – Joshua Sortino Feb 06 '11 at 00:33
  • The above inserts a style element into the svg. Yes it's possible to insert an xhtml link element too for linking to an external stylesheet, or possibly an xml-stylesheet processing instruction (see http://www.w3.org/Style/styling-XML.html). – Erik Dahlström Feb 06 '11 at 11:32
  • This is pretty awesome Erik! However, I couldn't manage to get this trick to work in Chrome without including svgweb: http://code.google.com/p/svgweb/ ...Any idea's what I'm doing wrong? – Matt W-D Jul 14 '12 at 23:48
  • 1
    @MattW-D: you should probably just open a new question for that. Svgweb is not needed in chrome. – Erik Dahlström Jul 15 '12 at 18:41
  • Thank You Erik, was really struggling trying to get font-face to work in svg through css, linking the css into the svg worked first try and miraculously cross browser! – Dave Nov 06 '13 at 03:26
  • The line `var svgDoc = yourObjectElement.contentDocument;` returns null. The only way I managed to get this working was with a load listener on the Element and inside it get the contentDocument as illustrated here: http://stackoverflow.com/questions/2753732/how-to-access-svg-elements-with-javascript – guibar May 16 '14 at 14:36
  • Thanks for the answer, it was enlightening :) – Ahmed Shehab Jun 06 '21 at 11:00
  • What do you mean by "yourObjectElement". I'm a little confused what should be replaced there. Would that also be a "getElementByID"? – Sam Sabin Feb 09 '23 at 23:26
  • Also what do you mean by the fact that the code assumes the object has already been loaded? Does that mean you couldn't change the SVG on page load, only afterwards using a button or something like that? – Sam Sabin Feb 10 '23 at 00:44
17

You can do this without javsscrpt by putting a style block with your styles inside the SVG file itself.

<style type="text/css">
 path,
 circle,
 polygon { 
    fill: #fff; 
  }
</style>
R Reveley
  • 1,547
  • 3
  • 14
  • 33
5

If the only reason for using the tag to inlcude the SVG is that you do not want to clutter your source code with the markup from the SVG, you should take a look at SVG injectors like SVGInject.

SVG injection uses Javascript to inject an SVG file inline into your HTML document. This allows for clean HTML source code while making the SVGs fully styleable with CSS. A basic example looks like this:

<html>
<head>
  <script src="svg-inject.min.js"></script>
</head>
<body>
  <img src="image.svg" onload="SVGInject(this)" />
</body>
</html>
Waruyama
  • 3,267
  • 1
  • 32
  • 42
1

Based on @Erik Dahlström answer, found a short path as follow:


let svg_objecst = document.getElementsByClassName('svg-object')

const forceStylingObjSvg = (svg)=>{
    var svgDoc = svg.contentDocument;
    svgDoc.firstElementChild.setAttribute('fill','blue')
}
Array.from(svg_objecst).forEach((obj)=>{
    obj.addEventListener('load',()=>forceStylingObjSvg(obj))
})


Ahmed Shehab
  • 1,657
  • 15
  • 24
0

You can create a custom element to inject the SVG file into your html.

This way, the SVG will be inlined, and you can easily apply styles using CSS.

This custom element will work just like the <object> or <embed> tags. The only difference is that <object> or <embed> tags injects the data in a shadow root, which prevents styling from the parent document, while <custom-svg> injects the data in the document itself.

I have tried too many ways to style my SVG images, and this was the easiest and more flexible way i have found so far.

<html>
  <head>
    <style>
      .blue {
        fill: blue;
      }
      .red {
        fill: red;
      }
    </style>
  </head>
  <body>
    <custom-svg class="blue" src="icon.svg"></custom-svg>
    <custom-svg class="red" src="icon.svg"></custom-svg>

    <script>
      class CustomSVG extends HTMLElement {
        constructor() {
          super();
        }
        connectedCallback() {
          fetch(this.getAttribute('src'))
            .then(response => response.text())
            .then(text => {
              this.innerHTML = text;
            });
        }
      }
      customElements.define('custom-svg', CustomSVG);
    </script>
  </body>
</html>

Notes

  • The SVG image must not have the "fill" attribute if you want, for example, change the fill color using CSS.
0

custom-svg works very good, for width style use this:

custom-svg svg{
  max-width:64px;
  max-height:64px;
  }