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>