Home > OS >  Restrict CSS in .SVG file to that SVG only
Restrict CSS in .SVG file to that SVG only

Time:01-06

We use Umbraco for our customers, and we want to allow them to change icons for certain content. It's possible to upload and select a custom SVG.

Because we work on a template base, we want to control the color of the icons. Using javascript, we transform the with an SVG to a HTML -tag. That way, we can alter the fill of stroke in the SVG's using regular CSS.

But we ran into an issue, where a customer had uploaded multiple SVG icons which were all having internal CSS and using the same class-names for paths, circles and what not.

The problem is, the last SVG that's on the page overrules the CSS for all SVG's. For example:

<svg ...>
    <defs>
        <style>.a{fill: red;}</style>
    </defs>
    <circle  cx="50" cy="50" r="50" />
</svg>

<svg ...>
    <defs>
        <style>.a{fill: blue;}</style>
    </defs>
    <circle  cx="50" cy="50" r="50" />
</svg>

The customer expects a red and a blue circle, because that's what he selected within the CMS. But this renders to 2 blue circles.

Is there any way to keep CSS found in an SVG within that same SVG?

CodePudding user response:

With a hint from @Lain, I have changed the to script. It now add's a random-generated classname to the SVG, and prepends that classname to every class in the tag like this:

let styleTag = $svg.find('style');
if (styleTag.length) {    
    let svgClass = GenerateClassname(8);
    const regex = /\.([a-z]{1})/ig; // Get every . followed by a letter
    styleTag[0].innerHTML = styleTag[0].innerHTML.replace(regex, "."   svgClass  " .$1"); 
}

CodePudding user response:

And then, in your near future, you do want to style those individual elements with (global) styling.

  • shadowDOM (optional part of the native Web Components spec aka Custom Elements)
    was created for use-cases like these
  • "outside/global" CSS does not leak in
  • "inside" CSS does not leak out
  • and inheritable styles, CSS properties and CSS :part can style your shadowDOM

customElements.define("svg-circle", class extends HTMLElement{
  connectedCallback(){
    this.style.display = "inline-block";
    this.style.width   = "15vw";
    this.attachShadow({mode:"open"})
        .innerHTML = `<svg viewBox="0 0 100 100">
                        <style>.a { fill:${this.getAttribute("color")} }</style>
                        <circle               cx="50" cy="50" r="45" />
                        <circle part="inner"  cx="50" cy="50" r="20" />
                      </svg>`;
  }
});
<style>
  *::part(inner){ fill:hotpink } /* higher Specificity */
</style>

<h2>Who is afraid of</h2>
<svg-circle color="red"    ></svg-circle>
<svg-circle color="yellow" ></svg-circle>
<svg-circle color="blue"   ></svg-circle>

  • Related