Is it possible to use css variables inside inline svg? - css

I am writing a userstyle for a website, I use css variables for configuration by the user. I am trying to use inline svg with a variable in it to create a checkmark set to the user's preferred accent color. But it doesn't seem to work.
In the code provided I just jammed in the var function, but I've also tried setting the color of the stroke to currentColor and setting the color of the element to the variable. Setting the mask and background-color work but I want a "pure inline svg" solution.
.checkmark {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12">\
<path fill="none" stroke="var(--ColAccent)" stroke-width="3" d="M1.99609375 5.7835338l3.70287382 3.7028738L14.1853752 1"/>\
</svg>');
}
The checkmark should be accent color. When I set it by simply putting in the var() it doesn't work and is transparent. Interestingly, when using the currentColor method, the stroke is black.

This is working:
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" style="--ColAccent:red">
<path fill="none" style="stroke:var(--ColAccent)" stroke-width="3" d="M1.99609375 5.7835338l3.70287382 3.7028738L14.1853752 1"/>
</svg>
This is not working:
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='--ColAccent:red' width='16' height='12'%3E%3Cpath fill='none' style='stroke:var(--ColAccent)' stroke-width='3' d='M1.99609375 5.7835338l3.70287382 3.7028738L14.1853752 1'/%3E%3C/svg%3E%0A")'
For a solution to your problem I would use javascript:
let _checkmark = document.querySelector(".checkmark");
let ColAccent = _checkmark.style.getPropertyValue("--ColAccent");
_checkmark.style.backgroundImage = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='12'%3E%3Cpath fill='none' stroke='${ColAccent}' stroke-width='3' d='M1.99609375 5.7835338l3.70287382 3.7028738L14.1853752 1'/%3E%3C/svg%3E%0A")`
.checkmark {
width:100px;
height:100px;
border:1px solid;
}
<div class="checkmark" style="--ColAccent:skyBlue" ></div>

I don't think it is possible to directly use css variables inside inline svg because the inline svg isn't directly in the DOM and you can't target it using css (i.e., there is no way to target the svg from .checkmark class. The only other option is to use javascript getPropertyValue to get the value of the css variable --ColAccent and use it to create a url string with a valid colorname (i.e., red) or URI encoded color value (i.e., %23f00 which is decoded to #f00) for stroke. Since you can't use javascript, I can't think of any other way.

Related

Color changeable SVG?

I wish to build a website where icon colors can be easily changed with the only change of the css. I've been given a set of custom icons in form of svg files.
I've already experimented with background color, filters and alike (see https://codesandbox.io/s/exciting-montalcini-xfufu?file=/index.html).
Which is the best technique to use? Should I generate a font from the SVGs?
First, open your SVG file and change the style of the .cls-1 path:
.cls-1 { fill: currentColor; }
Now place the SVG inside your HTML code. The color of the shield will follow the current font color. The <use> tag will allow you to duplicate it easily. Just make sure to hide the original instance of the SVG with style="display: none;".
svg {
width: 42px;
height: 50px;
}
.green-icon { color: green; }
.red-icon { color: red; }
.blue-icon { color: blue; }
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 768.42 907.1" style="display: none;"><defs><style>.cls-1{fill:currentColor;}.cls-2{fill:#fff;}</style></defs><g id="Livello_2" data-name="Livello 2"><g id="Layer_1" data-name="Layer 1"><path class="cls-1" d="M766.27,141.2c-157.6,0-279.1-44.3-382.5-141.2C282,97.7,160.47,141.2,2.07,141.2c0,253.7-53.4,618.2,382.5,765.9C820.47,758.6,766.27,394.9,766.27,141.2Z"/><path class="cls-2" d="M449.87,436.6a43.42,43.42,0,0,1,28.9-7.1l113.9-114-63.8-63.8L415,365.7a42.67,42.67,0,0,1-7.4,29.2Z"/><polygon class="cls-2" points="251.17 575.4 246.97 571.3 225.37 588.8 188.97 646.1 198.37 655.4 255.67 619 273.17 597.5 268.97 593.3 341.47 520.8 323.47 503.1 251.17 575.4"/><path class="cls-2" d="M350.27,374.5a88.86,88.86,0,0,0-108.9-109.8l50.4,50.3-13.2,49.3-49.4,13.2-50.3-50.3a88.86,88.86,0,0,0,113.5,107.7l.3.3,207.1,207.1a42,42,0,0,0,59.4-59.4Zm182.8,261a16,16,0,1,1,16.1-16A16,16,0,0,1,533.07,635.5Z"/></g></g></svg>
<svg class="green-icon" viewBox="0 0 768.42 907.1"><use href="#Layer_1"></use></svg>
<svg class="red-icon" viewBox="0 0 768.42 907.1"><use href="#Layer_1"></use></svg>
<svg class="blue-icon" viewBox="0 0 768.42 907.1"><use href="#Layer_1"></use></svg>
(This solution is based on this article from CSS Tricks.)
Generating a custom icon font would property be the best idea, since you have the fastest implementation in your HTML markup and don't have to care about embedding images again an again anymore.
https://icomoon.io is a great generator when you are looking for a helper software to generate your font.

How to apply startOffset in the style-section of an svg for all textPath elements?

Putting the startOffset-setting in the textPath's tag does work (startOffset=" 20%")
But as I have quite a lot of textPaths, I want to put this setting in the style.
How to do that? Is it possible?
<svg width="1059" height="637" viewBox="0 0 1059 637" xmlns="http://www.w3.org/2000/svg">
<style> <![CDATA[ * { font-family: Corbel;font-size: 12px;font-weight: normal;font-style: normal;fill: #0000ff;text-anchor: start;white-space: pre;startOffset: 40%;method: align;text-decoration: none none;text-transform: none;font-variant: normal;text-shadow: none;word-spacing: 0px;letter-spacing: 0px;font-stretch: normal; }
textPath { startOffset:" 20%" } ]]> </style>
<defs>
<path id="a131" d="M46.5,172.5L57.5,172.5L63.5,172.5L65.5,172.5L72.5,172.5L73.5,172.5L77.5,172.5L82.5,172.5" />
</defs>
<text>
<textPath href="#a131"> Test Text Test Text</textPath>
</text> </svg>
Is it because it's an attribute instead of a property?
startOffset is an attribute and not a CSS property so cannot be set via CSS. (method seems to be another attribute relevant to my program.)
There are SVG presentation attributes that are CSS properties that can be used as attributes on SVG elements. The other way around that SVG elements' original attributes could be used in CSS styling, doesn't work.

CSS how to warp/bend an image or div?

Hi,
Is it possible to achieve this effect with CSS only?
As you can see, the image on top is distorted along with the text inside to look like the one below. It may be a div or an image. I have been researching on transform but found nothing about curves.
This is NOT a duplicate because I am not asking how to curve the text only but the div container as well as in case of an image.
Thank you.
I don't know if you would technically qualify this as "CSS only" since it is using an SVG filter, but I think it could be made to achieve the type of warping you want.
.warped {
display: inline-block;
background-color: yellow;
padding: 4px;
filter: url(#displacement);
}
#filterSource {
display: none;
}
<span class="warped">Warped Text!</span>
<div>
<svg id="filterSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="displacement" filterUnits="userSpaceOnUse">
<!-- this is just a base64 encoded PNG with a simple linear gradient -->
<!-- this may not be exactly what you want, but you can adjust the R and B channels to displace the element however you like. -->
<feImage href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAdhAAAHYQGVw7i2AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAGlJREFUaIHtz6ENwEAMxVBfUWn3H7Kw8LpCdMjAT/osIF7AZuAGnsMt4D3cN3kOuIZ3eoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNoXYFGJTiE0hNj9ceBBjuV6HJAAAAABJRU5ErkJggg==" result="dispMap" />
<feDisplacementMap
in="SourceGraphic"
in2="dispMap"
scale="10"
xChannelSelector="B"
yChannelSelector="R" />
</filter>
</defs>
</svg>
</div>
Here's a nice tutorial on some cool effects you can achieve with this technique: https://www.creativebloq.com/how-to/add-svg-filters-with-css

SVG - Accessing individual nodes on xlink:href external source

I was looking at Chris Coier's SVG tricks on CSS-tricks.com and also recently saw him at a conference where he talked about the powers of SVGs and how you can keep all assets in one external svg file.
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="beaker" viewBox="214.7 0 182.6 792">
<!-- <path>s and whatever other shapes in here -->
</symbol>
<symbol id="shape-icon-2" viewBox="0 26 100 48">
<!-- <path>s and whatever other shapes in here -->
</symbol>
</svg>
Then, you could just use it like this:
<svg class="icon">
<use xlink:href="#shape-icon-1" />
</svg>
<svg class="icon">
<use xlink:href="#shape-icon-2" />
</svg>
Sounds great! BUT, I want to be able to access individual nodes in each symbol and altering them with CSS like I normally would if the SVG was inline in the HTMl.
Take a look at this CodePen:
http://codepen.io/chriscoyier/pen/Hwcxp
I thought I could do this, but I can't get it to work:
.icon path{
fill: green;
}
This does, but this alters the actual source svg
#beaker path {
fill: green;
}
What I want to do is reuse a graphical element in a grid. And on hover, alter a node in the svg. But only on the node in that particular parent. Not all of them.
Firefox does some unknown thing where you can style it this way.
edit:
To be more precise:
Firefox seems to turn that symbol kinda into in the DOM.
http://codepen.io/Type-Style/pen/EaGbam
.hoverME:hover path, .hoverME:hover circle {
fill: red;
}
This also works with an external file. (Unfortunatly it does not with crossDomain Files)
"But you can insert just the class name of the path. That will work."
I mean as long as you stay within the SVG with your selectors it will work.
circle:hover, path:hover {
fill: red;
}

Precise SVG mouseovers in CSS and HTML

I have a geometic shape that I would like to fill in, pictured
When the mouse is hovered over each area, I would like it to fill in, pictured here.
Unfortunately, when I add in the rest of the shapes, my code does not work, as my browser is giving each shape a bounding box that covers the rest of the shapes. How can I make the mouseover shape of my svg precise and not a box?
Here is my HTML code:
<object data="images/logo/middle.svg"
type="image/svg+xml" class="middlesvg hoversvg" > <!-- only the middle is shown for brevity -->
</object>
CSS
.hoversvg
{
opacity: 0;
}
.hoversvg:hover{
opacity: 1;
}
You could do it straight in the SVG, no CSS required.
Draw each segment as its own polygon or path, and add a set attributeName tag into it:
<path … id="path1"><set attributeName="opacity" from="0" to="1.0" begin="path1.mouseover" end="path1.mouseout"/></path>
<path … id="path1"><set attributeName="opacity" from="0" to="1.0" begin="path2.mouseover" end="path2.mouseout"/></path>
etc.
This page has a bit more detail http://www.ibm.com/developerworks/library/x-svgint/ (scroll down to Events)
You'd need to implement the hovering within the middle.svg file. That way you can target the specific shape you want to change on hover.
Give each <path> in the SVG an id, like:
<svg xmlns="http://www.w3.org/2000/svg">
<path id="first-path"/>
<path id="second-path"/>
</svg>
Then you can select the individual paths in JS (e.g. document.querySelector('#first-path')) and do whatever you want with it.
To fill in the inside of the path, you could do something like this in your CSS:
#first-path {
cursor: pointer;
pointer-events: fill;
}
#first-path:hover {
fill: rgba(255,255,255,0.5);
}

Resources