Re-using SVG gradient via CSS - css

So I know I can swap out a gradient fill on an svg with css, something like;
<svg width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
rect{fill:url(#GradientSwap1)}
</style>
<defs>
<linearGradient id="GradientSwap1">
<stop offset="5%" stop-color="#F00" />
<stop offset="95%" stop-color="#999" />
</linearGradient>
</defs>
<rect width="100" height="50"/>
</svg>
and using ng-class I can swap out more than one of these gradients, except I can only get it to work if I include the <linearGradient> in the defs embedded into each SVG.
My question is, and what I can't seem to figure out. Is there a way to pull these gradient defs out of the SVG and make them into a resource I can use in others? Like in the .NET / XAML world, it would be really easy for me to pull them out, throw them in a resource dictionary, and use the same ones all over the place for whatever I like.
So is there an html5/css3/angular approach to the same conundrum? The idea of having to have to multiple SVG's with potentially multiple of the same Gradient defs reiterated for every single one just sounds wrong.

You should be able to define the gradient once and then call it in the CSS to apply anywhere. You could apply to all svgs or give it a class.
<svg>
<defs>
<linearGradient id="GradientSwap1">
<stop offset="5%" stop-color="#F00"></stop>
<stop offset="95%" stop-color="#999"></stop>
</linearGradient>
</defs>
<section>
<svg class="icon shape-facebook">
<path d="M28.3,62V35.2h-5.5v-9.4h5.6v-7.7c0,0,0.3-9.8,9.8-9.8s9.5,0,9.5,0v9.2H42.1c0,0-2.699,0-2.699,2.7c0,2.7,0,5.8,0,5.8H48
l-1.1,9.4H39.6V62H28.3z"></path>
</svg>
<svg class="icon shape-heart" x="0" y="0">
<path d="M35.645,59.413c0,0,26.949-19.601,26.949-34.12c0-16.752-22.049-22.047-26.949-1.674
c-4.9-20.373-26.95-15.078-26.95,1.674C8.695,39.812,35.645,59.413,35.645,59.413z"></path>
</svg>
.shape-heart { fill: url('#GradientSwap1'); }
http://jsfiddle.net/v6osyy5v/1/

Related

Why is my SVG's radialGradient NOT showing in Chrome based browsers, but does in Firefox?

Problem
My <radialGradient> for the ellipses below won't show in Chrome based browsers, but will show the other content. Whereas firefox will show both.
I read this page, and this page, and they gave clues that it was a radialGradient issue, but I'm not dealing with any external files like the first page has, nor trying a conical gradient like the other one.
Goal
I want to have my first <svg> tag strictly for <defs> only, so I can reference parts later on to cut down the file size, and keep it clean. And to get rid of blank space, I added style="display: none;" to this first <svg> tag.
What I tried
Once I do the above, I add my other <svg>'s (email, SMS, etc) to reference them many times. Again, the first blank svg with the defs does not show (which is good), and the <path>, ellipses, etc. will show fine in Firefox, but not Chrome.
The ellipses will only show in Chrome when I take off style="display: none;" from the first svg, even though they're in the same element.
When I noticed it might be a <radialGradient> issue, I added fill:yellow;stroke:purple;stroke-width:2 to my ellipses style attribute, and that makes the ellipse show with that styling, so I know the ellipse is there, but the gradient won't show inside it.
Anyone know why the <radialGradient> will not show up in Chrome based browsers while style="display: none;" is on the first svg??? Or does anyone have any work arounds to fix this / do this more efficiently??? I know I can put everything in 1 svg, but I need them all separate so I can style them with css more easily, since they're all icons.
Thanks!
<!DOCTYPE html>
<html>
<body>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
style="display:none;"
>
<defs>
<symbol id="ellipsesymbol" viewBox="0 0 126 76">
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(62.5,0,0,37.5,62.5069,37.5066)">
<stop offset="0" style="stop-color:#000;stop-opacity:0.5"/>
<stop offset="0.62" style="stop-color:#170725;stop-opacity:0.58"/>
<stop offset="0.82" style="stop-color:#4e187f;stop-opacity:0.78"/>
<stop offset="1" style="stop-color:#8a2be2;stop-opacity:1"/>
</radialGradient>
<ellipse cx="62.5" cy="37.839" rx="62.5" ry="37.5" style="fill:url(#_Radial1);" />
</symbol>
<symbol id="emailsymbol" viewBox="0 0 126 76">
<path
d="M31.15,17.125l0,40.763l62.713,0l0,-40.763l-62.713,-0Zm36.687,24.928c-1.411,1.411 -3.292,2.195 -5.33,2.195c-2.038,0 -3.92,-0.784 -5.331,-2.195l-21.792,-21.792l54.089,-0l-21.636,21.792Zm-17.402,-4.546l-16.149,16.148l0,-32.297l16.149,16.149Zm1.097,1.097l4.547,4.547c1.724,1.724 4.076,2.665 6.428,2.665c2.508,0 4.703,-0.941 6.428,-2.665l4.547,-4.547l16.148,16.149l-54.246,-0l16.148,-16.149Zm23.047,-1.097l16.149,-16.149l-0,32.454l-16.149,-16.305Z"
style="fill:#00bfff;fill-rule:nonzero;"/>
</symbol>
<symbol id="SMSsymbol" viewBox="0 0 126 76">
<path d="M98.587,27.064c0,-4.29 -3.483,-7.773 -7.773,-7.773l-56.464,0c-4.29,0 -7.773,3.483 -7.773,7.773l0,15.546c0,4.29 3.483,7.773 7.773,7.773l15.631,0l-9.002,13.326l19.803,-13.326l30.032,0c4.29,0 7.773,-3.483 7.773,-7.773l0,-15.546Z"
style="fill:#00bfff;"/>
<text x="36.276px" y="42.521px" style="font-family:'KnightsTemplar', 'Knights Templar';font-size:25.665px;">SMS</text>
</symbol>
<!-- .... -->
</defs>
</svg>
<svg id="emailgroup">
<use xlink:href="#ellipsesymbol" />
<use xlink:href="#emailsymbol" />
</svg>
<svg id="smsgroup">
<use xlink:href="#ellipsesymbol" />
<use xlink:href="#SMSsymbol" />
</svg>
<!-- more svg's.... -->
</body>
</html>
Instead of display:none, you can hide the first SVG with width="0" height="0". Then it works in Chrome:
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<symbol id="ellipsesymbol" viewBox="0 0 126 76">
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(62.5,0,0,37.5,62.5069,37.5066)">
<stop offset="0" style="stop-color:#000;stop-opacity:0.5"/>
<stop offset="0.62" style="stop-color:#170725;stop-opacity:0.58"/>
<stop offset="0.82" style="stop-color:#4e187f;stop-opacity:0.78"/>
<stop offset="1" style="stop-color:#8a2be2;stop-opacity:1"/>
</radialGradient>
<ellipse cx="62.5" cy="37.839" rx="62.5" ry="37.5" style="fill:url(#_Radial1);" />
</symbol>
<symbol id="emailsymbol" viewBox="0 0 126 76">
<path d="M31.15,17.125l0,40.763l62.713,0l0,-40.763l-62.713,-0Zm36.687,24.928c-1.411,1.411 -3.292,2.195 -5.33,2.195c-2.038,0 -3.92,-0.784 -5.331,-2.195l-21.792,-21.792l54.089,-0l-21.636,21.792Zm-17.402,-4.546l-16.149,16.148l0,-32.297l16.149,16.149Zm1.097,1.097l4.547,4.547c1.724,1.724 4.076,2.665 6.428,2.665c2.508,0 4.703,-0.941 6.428,-2.665l4.547,-4.547l16.148,16.149l-54.246,-0l16.148,-16.149Zm23.047,-1.097l16.149,-16.149l-0,32.454l-16.149,-16.305Z"
style="fill:#00bfff;fill-rule:nonzero;"/>
</symbol>
<symbol id="SMSsymbol" viewBox="0 0 126 76">
<path d="M98.587,27.064c0,-4.29 -3.483,-7.773 -7.773,-7.773l-56.464,0c-4.29,0 -7.773,3.483 -7.773,7.773l0,15.546c0,4.29 3.483,7.773 7.773,7.773l15.631,0l-9.002,13.326l19.803,-13.326l30.032,0c4.29,0 7.773,-3.483 7.773,-7.773l0,-15.546Z"
style="fill:#00bfff;"/>
<text x="36.276px" y="42.521px" style="font-family:'KnightsTemplar', 'Knights Templar';font-size:25.665px;">SMS</text>
</symbol>
</defs>
</svg>
<svg id="emailgroup">
<use href="#ellipsesymbol" />
<use href="#emailsymbol" />
</svg>
<svg id="smsgroup">
<use href="#ellipsesymbol" />
<use href="#SMSsymbol" />
</svg>
Also note that xlink:href is deprecated, and you can simply use href now:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href

Is it possible to animate a linear gradient gradientTransform property of an svg image

I have a simple outer circle svg created with the following code
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
id="Layer_1"
data-name="Layer 1"
viewBox="0 0 260 260">
<style>
.class1 {
fill-opacity:1;
fill:url(#grayGradient);
}
</style>
<defs>
<linearGradient id="grayGradient"
gradientUnits="userSpaceOnUse"
x1="0" y1="130" x2="260" y2="130">
<stop offset="0" style="stop-color:#919191;stop-opacity:1;" />
<stop offset="1" style="stop-color:#919191;stop-opacity:0;" />
</linearGradient>
</defs>
<title>outer circle</title>
<path
d="M130,0A130,130,0,1,0,260,130,130,130,0,0,0,130,0Zm.36,235a105,105,0,1,1,105-105A105,105,0,0,1,130.36,235Z"
class="class1" />
</svg>
I'm trying to make this look like an indeterminate progress circle, so I want to rotate the gradient around the path of the circle. I know that if I add a gradientTransform=rotate() attribute to the linearGradient, it will move the position of the gradient in the circle.
Is it possible to animate the gradientTransform so that it will appear that the circle is spinning?
I'm very new to svg. Perhaps there is a better way to achieve the effect I'm looking for? I do need to use an svg image that has the same shape.
Thanks for any and all suggestions...
Just add inside <linearGradient> ... </linearGradient> this string:
<animateTransform
attributeName="gradientTransform"
type="rotate"
from="0 130 130"
to="360 130 130"
dur="1s"
repeatCount="indefinite"
/>
But it won't work in IE and Safari.

Apply SVG Gradient filter to background image

I found this SVG code, and I was wondering how do I apply it to a background image?
<svg width="600px" height="600px" viewbox="0 0 600 600">
<defs>
<linearGradient id="alphaLinear">
<stop offset="0%" stop-color="#FFFFFF" stop-opacity="0%" />
<stop offset="100%" stop-color="#FFFFFF" stop-opacity="100%" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="600" height="600" fill="url(#alphaLinear)" />
</mask>
</defs>
<image xlink:href="/media/images/body-bg.jpg" width="600" height="600" x="0" y="0" preserveAspectRatio="xMinYMin meet" mask="url(#Mask)"/>
</svg>
In the <image> tag I replaced the href url with the image I want to use. I then call the svg from the css like so:
body{
background: url('/media/images/gradient.svg') center top no-repeat;
}
Nothing seems to be happening, all I am getting is a white background.
There are a few things wrong:
For external files, you will need the xmlns and xmlns:xlink namespace declarations in the <svg> tag.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="600px" height="600px" viewbox="0 0 600 600">
viewbox should be viewBox
SVG files used as an external image in <img> or as a background-image need to be self contained. They cannot refer to other external files as you are doing here.
You can embed the external JPEG as a Data URI though if you want.
<image xlink:href="data:image/jpeg;base64,...Base64 encoded JPEG data here...">

Gradient fill SVG after button click on HTML page

Is possible to fill SVG by gradient colors after a button is clicked on the page? I read a lot of articles here, but none helped me. I need the gradient colors only in css (The best option).
Here's an example where I need to apply for "metalic colors" - http://web-stranky.org/pro_dementa/
I would be grateful for any help.
Svg yet not support CSS3 gradient property, although you can fill gradient in svg by defining gradient in svg and using fill property to attain gradient fill in svg.
<svg height="150" width="400">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
</defs>
<ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" />
</svg>
for more details
http://www.w3schools.com/svg/svg_grad_linear.asp

Creating a linear gradient SVG filter

Essentially I'm trying to create an gradient alpha mask in using SVG and CSS (like this), and since the mask property is no longer on the standards track I'm exploring the filter route.
I've created a vertical alpha mask in Sketch, with the top being 0% #000000 and the bottom being 100% #000000, then exported it as an SVG and tweaked it using guidance from this O' Reilly article. It now looks like this:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<!-- Start by creating our vertical linear gradient -->
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="alphaLinear">
<stop offset="0%" style="stop-color: #000000; stop-opacity: 0%;" />
<stop offset="100%" style="stop-color: #000000; stop-opacity: 100%;" />
</linearGradient>
<!-- Create a rectangle and apply the gradient as its fill -->
<rect id="boxRect" x="0" y="0" width="100%" height="200" style="fill: url(#alphaLinear);" />
<!-- Using that rectangle, we'll create a filter -->
<filter id="alphaGrad">
<feImage xlink:href="#boxRect" result="grad"/>
<feDisplacementMap scale="10" xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" in2="grad"/>
</filter>
</defs>
<use id="gradientBox" fill="url(#alphaGradient)" xlink:href="#boxRect"></use>
</svg>
My knowledge of SVG isn't the greatest so I'm suspecting this is where I've gone wrong.
Next, I applied the filter using filter (and -webkit-filter) along with referencing the filter ID #alphaGrad:
-webkit-filter: url('http://blahblah.com/alphagradient.svg#alphaGrad');
But, of course, this it doesn't work. Can anyone help me get the hang of this? Or is this even possible? If not, can someone recommend a method of how to achieve this?
Thanks in advance!
Update: here's a pretty basic fiddle of what I'm doing...
There are many errors and misconceptions in your example (why did you think a displacementMap would help you?)
Why don't you start from the code below - pure SVG using an SVG mask and an SVG image.
<svg width="600px" height="600px" viewbox="0 0 600 600">
<defs>
<linearGradient id="alphaLinear">
<stop offset="0%" stop-color="#FFFFFF" stop-opacity="0%" />
<stop offset="100%" stop-color="#999999" stop-opacity="100%" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="600" height="600" fill="url(#alphaLinear)" />
</mask>
</defs>
<image xlink:href="http://upload.wikimedia.org/wikipedia/commons/7/71/Anadama_bread_(1).jpg" width="600" height="600" x="0" y="0" preserveAspectRatio="xMinYMin meet" mask="url(#Mask)"/>
</svg>
Few remarks:
SVG (and CSS) opacity value is not percertentual range but 0.0 - 1.0 range.
Mentioned mask property appears to be just prefixed in Webkit and unprefixed in Gecko.
If your target environment is HTML + CSS, you might not necessarily need SVG: you could get similar effect using linear-gradient and RGBA
background-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 50%); on some overlay (pseudo) element. pointer-events: none; could be useful then.

Resources