My team are shifting to svg icons.
We use to define the icons in css style classes, and are now considering whether SVG icons should be implemented as view component rendering svg markup (instead of html). This should allow for better reuse svg by changing dimensions, color etc. On the other hand this takes the icons out of the styling domain and any style change will cause code change (and not only css change).
Whats is the right way (if there any) to work with svg icons, control size and colors, and still save style layer and view layer?
SVG editors sometimes put style information inline, but style information for SVGs can also be provided inside <style> tags, as usual CSS.
If the SVG is in your DOM (the simplest way to do this, is to write the SVG directly into your HTML) the SVG can be formatted directly from your usual CSS file:
p {
color: #666;
}
.blueTriangle {
fill: lightblue;
stroke: #666;
stroke-width: 8;
}
<p> This is usual text in HTML p tags. </p>
<p> The next thing is embedded SVG, styled by usual CSS: </p>
<svg width="250" height="120">
<path class="blueTriangle" d="M150 20 L130 90 L170 90 Z" />
</svg>
With transform also scaling and rotations can be done, showing different components can be accomplished via display, visibility or opacity with different implications.
Changing paths themselves would be considered as changing the content of the file and can be done via JavaScript. Therefore the separation of style an content can still be preserved.
Related
I have an SVG image and I'm looking to change part of its color.
The SVG will always consist of 2 colors, i.e. black & yellow
I'm looking to change the yellow color with a css class, so I could switch to another color theme easily without creating all the svg buttons in the yellow version.
Is this at all possible? I can't seem to find much online about this..
The SVG is set on span/div's using a class with background-image
If i implement the tag with SVG then I can change the color with css. But I'm looking to use it as a class if possible (and the svg should not be directly in the html)
<svg>
<use xlink:href="#robot" id="robot-1" />
</svg>
Turorial:
https://tympanus.net/codrops/2015/07/16/styling-svg-use-content-css/
JsFiddle:
https://jsfiddle.net/wahjvmnq/
You can change all the paths using --secondary-color to be fill: currentColor and then wrap the SVG with an HTML element that has a CSS class or styles applied to it that updates the color property.
After updating the path's in the SVG that currently use --secondary-color:
<div style="color:red;">
<svg>
<use xlink:href="#robot" id="robot-1" />
</svg>
</div>
Here is an example on jsFiddle where the yellow has been changed to red.
You can not override the SVG colors with CSS unless it is part of the HTML document.
I'm using inline <svg> for my icons on an html page. I have a component which renders a table, often with hundreds of rows. In this case, every row of the table has the same inlined svg. Usually they are simple icons with just a few paths, but it got me wondering if there is some way to optimise this. In this scenario inlining is important, I don't want to have references to any external files. Is there some way for me to have the inlined svg just once, and refer to that same element somewhere else? Is this something I should even be worried about? Is the overhead of repeating inline svgs minimal?
If you have hundreds of table rows with one SVG, they all are (SVG) DOM elements you have to duplicate/repeat. There is no equivalent to SVGs use in HTML (you could built that yourself with a Custom Element)
If performance really really is an issue you need to test if creating SVGs Server Side (SSR) performs better (in your use case) than creating SVGs Client-Side... but you're probably talking micro-seconds..
The Custom Element IconMeister (one of my pet projects) creates all used SVG icons Client side
(you can cherry pick from 7000+ icons)
Or if all your SVGs are 100% duplicates just a one liner with native JS cloneNode could be enough.
Or create a very simple IconMeister yourself in a W3C Standard Custom Element
for clean semantic HTML:
(100% supported in all modern Browsers, supported by all Frameworks... except React)
<style>
svg-icon svg {
--size: 120px;
width: var(--size);
height: var(--size);
}
[bg=blue] svg{
width:1px;
}
[bg=yellow] svg{
width:5px;
}
</style>
<h3>Who is afraid of Red, Yellow and Blue</h3>
<svg-icon bg="red" ></svg-icon>
<svg-icon bg="yellow" ></svg-icon>
<svg-icon bg="blue" ></svg-icon>
<script>
customElements.define( "svg-icon", class extends HTMLElement {
connectedCallback() {
this.innerHTML =
`<svg xmlns='http://www.w3.org/2000/svg'>` +
`<rect width='100%' height='100%' fill='${this.getAttribute("bg")}'/>` +
`</svg>`;
}});
</script>
When using a CSS reset like
* {
all: unset;
}
inline SVG graphics are not shown correctly, see https://jsfiddle.net/593qysxp/1/
I have tested this with Safari 11 and Chrome 61.
I tried to solve this with setting the svg element to display: block or all: initialbut this did not help.
Does anyone has a solution?
If you want to leave SVG content completely alone and not reset anything inside them, you could use
#namespace svg "http://www.w3.org/2000/svg";
:not(svg|*) {
all: unset;
}
SVG 2 now defines a number of attributes as presentation attributes that were true XML attributes in SVG 1.1. Among them are cx, cy, rx, ry for <ellipse> elements and the d attribute for <path> elements.
That has the consequence that these, when written as attributes on the element, are treated as CSS properties. That is why they are overwritten by all: unset. (according to SVG 1.1 rules, see Addendum below.)
That means equally that they can be stated in a style attribute, where they would have a higher specicifity than any stylesheet.
As not all browser implement these presentation attributes yet, you would have to state them for now double as attributes and style properties. The result looks weird, if you ask me:
* {
all: unset;
}
head, link, meta, script, style, title {
display: none;
}
div {
display: block;
}
.icon {
width: 4rem;
}
<div>
<svg class="icon icon--search" viewBox="0 0 20 20"
version="1.1" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="14.159" cy="5.87" rx="5.89" ry="5.849"
style="fill:none;stroke:#000000;stroke-width:1px;cx:14.159px;cy:5.87px;rx:5.89px;ry:5.849px"/>
<path d="M10,10l-9.98,10.02"
style="fill:none;stroke:#000000;stroke-width:1px;d:path('M10,10l-9.98,10.02')"/>
</svg>
</div>
The use of the path() functional notation is, by the way, still an open issue. So this may currently work, but not for long. This whole technique looks like something that I would not advise to use.
Addendum: Things get further complicated by a breaking change in the SVG spec I wasn't aware of until I just read up on it. SVG 1.1 has this to say about the CSS cascade:
The presentation attributes thus will participate in the CSS2 cascade as if they were replaced by corresponding CSS style rules placed at the start of the author style sheet with a specificity of zero.
SVG 2 instead says this:
Presentation attributes contribute to the author level of the cascade, following all other author-level style sheets, and have specificity 0.
First or last? So far I have not encountered any browser where presentation attributes supplant author style sheet rules. That includes this example. Following SVG 2 rules, your stylesheet rule should have been replaced by the attributes, but obviously weren't.
I am playing around with SVGs (trying to replace icon fonts with SVG.) I got it to render the image/svg using object tag. However, I can't get it to change color from CSS. Assuming, I prefer coloring it from CSS, is there a way to do that while I use to embed SVG.
<object class="partnerLogo" type="image/svg+xml" data="assets/logos/sample.svg">
Your browser does not support SVG
</object>
CSS, I tried so far:
.partnerLogo {
width: 100%;
height: 100px;
color: red;
color-fill: red;
}
In sample.svg file, I added, <?xml-stylesheet type="text/css" href="../css/styles.css"?> just before
styles.css is being added to the page.
Thanks!
It isn't possible to directly modify the fill if you're using the SVG using the <object> method. The SVG is included as a document fragment inside the object tag, so your properties aren't passed as you can see in this image.
However, there are two ways you can modify the colors of an external SVG.
1) Use Javascript (recommended)
Using Javascript you can fetch the SVG contents via an XHR, and then inject it as inline SVG. As it's inline SVG technically, you can modify the fill color. There's a library I have written (svg-loader) that make it really easy to do this.
You just need to include the library and use data-src attributes to load SVGs.
Example:
Here, I have included a logo in three different formats, modifying the fill color.
<script type="text/javascript" src="https://unpkg.com/external-svg-loader#latest/svg-loader.min.js" async></script>
<div style="display:flex;">
<div style="background:black;">
<svg data-src="https://s2.svgbox.net/assets/logo-white.svg" fill="yellow"></svg>
</div>
<div style="background:purple;">
<svg data-src="https://s2.svgbox.net/assets/logo-white.svg" fill="white"></svg>
</div>
<div style="background:green;">
<svg data-src="https://s2.svgbox.net/assets/logo-white.svg" fill="red"></svg>
</div>
</div>
2) Use filter CSS property
You can use the filter CSS property to reach any color using bunch of operations (brightness, contrast, hue-rotate..). There an existing stack overflow discussion on this.
Example:
.red {
filter: invert(20%) sepia(97%) saturate(4013%) hue-rotate(353deg) brightness(93%) contrast(127%);
}
<img src="https://s2.svgbox.net/assets/logo-white.svg" class="red" />
The big drawback here is that you'd need to calculate this for every color (using this) and doesn't make it obvious how it works. Also, it won't work well with SVGs having multiple colors.
As far as I know, color in SVG-CSS should be stroke for borders and fill for backgrounds:
.partnerLogo {
width: 100%;
height: 100px;
stroke: red;
fill: red;
}
You can't use external CSS classes to style a SVG called within an < object > element, despite a lot of blog posts in the subject says you can interact with, buit this is misleading for this particular case. You must add the formattings inline, inside the actual SVG.
If you need to access and alter the actual objects and paths of an SVG from your main css file, you must embedd it inline, using the < svg > tag.
Here's a post that covers it all:
https://vecta.io/blog/best-way-to-embed-svg
I know this is an old question now - but this is for any future readers who want to colour their SVGs with pure CSS rather than have to use JS. I find this method quite convenient compared to other methods - and you can even colour your SVGs with a gradient etc.!
I simply make a div which will contain my SVG and give it a class.
HTML:
<div class="colourful-svg"></div>
Then the colour is done using masks and background colour in your CSS.
CSS:
.colourful-svg {
mask-image: url("path/to/your/svg-file.svg");
background: green;
// Make sure you define dimensions for your div otherwise it won't show up
height: 500px;
width: 500px;
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
}
This will make your SVG fill the div you had made and therefore be the size you need it to. It then uses a mask to essentially only show your background colour through the SVG you have linked to using the url() function.
Masks now have pretty good support with prefixes (about 94% globally from caniuse.com at the time of writing), so I think this is quite a simple and easy way to implement colour SVGs - I hope someone finds this useful!
Basically, I have a couple .svg images put into an <img> tag on my HTML page like that:
<img src="images/corner.svg" alt="menu" class="menu" onClick="Fade();"/>
All of those images are overlapping with each other. They have the same size but different content.
I'm now trying to make only the content of those images clickable.
With pointer-events: visible; or pointer-events: painted; in CSS that seemed to be possible, but i can't get it work like that. The image still receives clicks at every point in it and not only on the content part.
I tried pointer-events: none; on the top image and that disabled clicks on the top image, which sounded like there was no mistake in the HTML or CSS code.
I created those .svg images in Illustrator CC with a transparent background, so normally there can't be content, and I exported it with the following options:
(sorry for this being in german)
I have no idea where the problem could be.
I've had success inlining the SVG, setting the pointer-events to none for the SVG elements, and then setting the pointer-events for the path element within the SVG to fill. Here's a CodePen example.
svg {
cursor: pointer;
pointer-events: none;
}
path {
pointer-events: fill;
}
The problem is that you're using an <img> tag. They work like rasters even when the data is SVG i.e. the individual items don't really exist, it's just a picture which you can either have as entirey clickable or not.
If you want the drawing to be interactive you'll need to use an <object> or <iframe> tag and then you can make the individual shapes clickable or not by using the pointer-events attribute.
You could also include all the svg data inline in the html file but if you did that you'd need to make sure all the id attributes were unique.
This is what worked for me
svg {
pointer-events:none;
}
svg *{
pointer-events:auto;
}
don't hesitate to add !important in case it has conflict with your current style.