I am trying to avoid having to <use class="myicon" xlink:href="myicon" /> by simply targeting the value of the xlink:href attribute when styling my SVGs. None of the following selectors seem to work:
[xlink|href*=myicon], // I also set the namespace at the top of the file
[xlink:href*=myicon],
[xlink\:href*=myicon] {
color: yellow !important;
}
A few other questions on the site seem to imply that styling using the attribute selectors on namespaced attributes should be possible, even though plain html has no support for namespaced attributes, as it should just regard them as one word. But I cannot get it to work, so I am losing faith in just that.
As Blake Mann says, if you're listing all your selectors together like that, it won't work because [xlink:href*=myicon] is invalid, which causes your entire ruleset to be dropped. If you're trying different selectors, you need to try them one at a time.
[xlink|href*=myicon] works just fine, but make sure you've specified the XLink namespace and not the SVG namespace:
#namespace xlink 'http://www.w3.org/1999/xlink';
html {
background-color: black;
}
[xlink|href*=myicon] {
fill: yellow;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<text id="myicon" y="16">Icon</text>
</defs>
<use xlink:href="#myicon" />
</svg>
You were definitely on the right track with what you were doing.. in fact, you have the right answer:
[xlink\:href*=myicon] {
color: yellow !important;
}
The reason it isn't working is because the first two selectors you tried were invalid (both the | and : characters need to be escaped), and if a CSS selector contains invalid characters, the whole selector group gets thrown out.
Check this example as proof... the div (just using a div for simplicity, even though that's not quite right) should get set to be red, as that rule comes after the blue one, but because the selector group gets thrown out, that rule won't get applied. The other selector that does not have the invalid characters will apply though!
[xlink\:href*=myicon] {
color: blue;
}
[xlink|href*=myicon],
[xlink:href*=myicon],
[xlink\:href*=myicon] {
color: red;
}
<div xlink:href="myicon">Lorem Ipsum</div>
Related
I see that multiple attribute selectors are "and-ed" together for example:
/* Links that start with "https" and end in ".org" */
a[href^="https"][href$=".org"] {
color: green;
}
I there a way to express that I want to match all <a>s that have href containing one a, b or c?
Yes, you can target elements with one attribute value OR another in CSS.
Geat's selector list approach with commas , is the most straightforward, and also the most browser compatible:
a[href^="https"][href$=".org"][href*="a"],
a[href^="https"][href$=".org"][href*="b"],
a[href^="https"][href$=".org"][href*="c"] {
color: green;
}
https://a.org
https://b.org
https://c.org
https://d.org
http://a.org
I agree though that this can become cumbersome. Luckily we can use the modern CSS :is() pseudo class to shorten this selector:
a[href^="https"][href$=".org"]:is([href*="a"], [href*="b"], [href*="c"]) {
color: green;
}
https://a.org
https://b.org
https://c.org
https://d.org
http://a.org
This also has the benefit of making the selector list forgiving, where if one selector within :is() is invalid, the others will still work - a regular selector list in CSS is actually unforgiving and will break the entire list if one selector breaks!
Also note that both examples above will match A, B, C if they are contained within the protocol, path (any part of the URL) i.e.
a[href^="https"][href$=".org"]:is([href*="org"], [href*="http"], [href*="h"]) {
color: green;
}
https://org.org
https://s.org
https://x.org
https://y.org
http://website.org
Unfortunately, the substring syntax for attribute selectors in CSS does not currently feature a way to match A OR B in an elegant way like I've illustrated below which I'm sure is what you were hoping for:
a[href^="https"][href$=".org"][href*="a"|"b"|"c"]
This is my code css code.
img[src="https://media.istockphoto.com/photos/colored-powder-explosion-on-black-background-picture-id1140180560?k=20&m=1140180560&s=612x612&w=0&h=X_400OQDFQGqccORnKt2PHYvTZ3dBLeEnCH_hRiUQrY"]{
width:250px;
}
This is my html code
<img src="https://media.istockphoto.com/photos/colored-powder-explosion-on-black-background-picture-id1140180560?k=20&m=1140180560&s=612x612&w=0&h=X_400OQDFQGqccORnKt2PHYvTZ3dBLeEnCH_hRiUQrY=">
Your selector is different to the actual src. The code below fixes this problem and has the exact src.
The difference was that you appended an unnecessary = to the selector in CSS.
img[src="https://media.istockphoto.com/photos/colored-powder-explosion-on-black-background-picture-id1140180560?k=20&m=1140180560&s=612x612&w=0&h=X_400OQDFQGqccORnKt2PHYvTZ3dBLeEnCH_hRiUQrY="] {
width: 250px;
}
<img src="https://media.istockphoto.com/photos/colored-powder-explosion-on-black-background-picture-id1140180560?k=20&m=1140180560&s=612x612&w=0&h=X_400OQDFQGqccORnKt2PHYvTZ3dBLeEnCH_hRiUQrY=">
A better way would be to use .classes {} or #ids {} though.
More information about attribute selectors: MDN
More information about: Classes - MDN IDs - MDN
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 have a svg with different paths, ellipses etc. They have different fill colours. Say red & blue. Now, I put them all into a sprite, and would now like to modify fill colour with css on hover, so what I would normally do is remove the fills from the svg and do everything with css' fill property.
However, since I have different colours here, I cannot simply do fill:red, since everything will be red, but I want some of it to be blue.
You can add a different class to each of the paths:
<circle class="circleClass" cx="40" cy="50" r="26"/>
<square class="squareClass" cx="40" cy="50" r="26"/>
Then target those classes in your CSS:
.circleClass {
fill: red;
}
You can add a class to every path or you can use the nth-child.
Here is an easy example:
<path bla-bla-bla>
<path bla-bla-bla>
<path bla-bla-bla>
path:nth-child(1){
fill:red;
}
path:nth-child(2){
fill:blue;
}
path:nth-child(3){
fill:green;
}
What you are doing can't work. Anything referenced via a <use> is not present in the DOM under the <use> element.
.icon:hover .outer { }
won't work because the path with class outer is not a descendant of .icon. If you want to style the contents of a symbol, you need to do it by applying the ruules directly to the symbol. For example:
#btn-tester .outer { }
Unfortunately :hover events don't apply to symbols. So you can't do:
#btn-tester:hover .outer { }
Even if that worked, you may not want to do that anyway. If there were any other uses of the symbol on the page, it would change them also.
You probably are going to have to just inline the SVG on the page where you want it. Instead of using a symbol.
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!