Change svg gradient to solid white with a transition? - html

I can't seem to get a transition on an SVG when I hover it.
The svg has a gradient inside ... but I want it to transition to white on hover.
Any ideas?
svg {
width: 20px;
height: 20px;
path {
transition: fill 0.4s ease;
&:hover {
fill: $white;
}
}
}
<svg id="Facebook_icon" data-name="Facebook icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8.713" height="16.779" viewBox="0 0 8.713 16.779">
<defs>
<linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f7d077"/>
<stop offset="0.112" stop-color="#ffefaa"/>
<stop offset="0.269" stop-color="#ffdb74"/>
<stop offset="0.552" stop-color="#dba846"/>
<stop offset="0.808" stop-color="#dba846"/>
<stop offset="1" stop-color="#f4cd6f"/>
</linearGradient>
</defs>
<path id="Icon" d="M8.713,2.785H7.134c-1.238,0-1.479.588-1.479,1.451v1.9H8.61L8.225,9.125H5.655v7.653H2.576V9.125H0V6.142H2.576v-2.2A3.594,3.594,0,0,1,6.412,0a21.049,21.049,0,0,1,2.3.117Z" fill="url(#linear-gradient)"/>
</svg>

For CSSOM, a gradient is of type <image>, and you can't transition from an <image> to a solid <color>.
What you can do however is to transition from an <image> to an other <image>, so we should have been able to transition between two gradients, but as of this writing it seems no browser supports transitioning between svg gradients and none supports CSS gradients as fill value.
What does work however is to transition the stop-color values of the <stop> elements.
For this to happen only when the <path> is hovered, I did change the structure of your svg.
svg {
width: 20px;
height: 20px;
}
svg stop {
transition: stop-color 0.4s ease;
}
svg path:hover ~ defs stop {
stop-color: white;
}
<svg id="Facebook_icon" data-name="Facebook icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8.713" height="16.779" viewBox="0 0 8.713 16.779">
<path id="Icon" d="M8.713,2.785H7.134c-1.238,0-1.479.588-1.479,1.451v1.9H8.61L8.225,9.125H5.655v7.653H2.576V9.125H0V6.142H2.576v-2.2A3.594,3.594,0,0,1,6.412,0a21.049,21.049,0,0,1,2.3.117Z"
fill="url(#linear-gradient)"/>
<defs>
<linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f7d077"/>
<stop offset="0.112" stop-color="#ffefaa"/>
<stop offset="0.269" stop-color="#ffdb74"/>
<stop offset="0.552" stop-color="#dba846"/>
<stop offset="0.808" stop-color="#dba846"/>
<stop offset="1" stop-color="#f4cd6f"/>
</linearGradient>
</defs>
</svg>

Related

Responsive <img> for svg has overflow

I am trying to have an <img src="*.svg"> tag to display (any) svg file, however with what I have so far there is some overflow of the svg's viewbox when it fills the width:
If I did not need absolute positioning, it works without any overlfow if you remove display: inline-block and use max-width and max-height, but since I need the image to fill its container, I have to use inline-block.
Thanks in advance for any help .
#inner-map {
display: inline-block;
position: relative;
}
#map-svg {
border-style: solid;
}
#map-svg img {
width: 100%;
height: 80vh;
display: block;
}
#pog-outer {
position: absolute;
}
#pog-inner {
position: absolute;
left:-9px;
top:-9px;
}
<div id="inner-map">
<div id="pog-outer" style="top:58.794%;left:28.915%">
<div id="pog-inner">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="18" height="18">
<defs>
<radialGradient id="Shiny" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
<stop offset="0%" stop-color="#FFFFFF" />
<stop offset="50%" stop-color="#DD3333" />
<stop offset="75%" stop-color="#990000" />
<stop offset="100%" stop-color="#000000" />
</radialGradient>
</defs>
<circle r="6" cx="9" cy="9" fill="url(#Shiny)" />
</svg>
</div>
</div>
<div id="map-svg">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d5/North_America_laea_location_map.svg">
</div>
</div>
Per the question's comments you want the image to fill the whole container and then if the aspect ratio of the image and its container differ, some edges of the image would overflow and are no longer be visible.
So to get that we'd want the image to have have preserveAspectRatio="xMidYMid slice" on its root element but unfortunately it doesn't. It doesn't have that attribute at all and the default if you have a viewBox is preserveAspectRatio="xMidYMid meet"
We'll need to override that value by using an SVG fragment identifier.
To make the example below more obvious I've also changed the width to width: 70vh; so it always overflows. You probably don't want to do that.
#inner-map {
display: inline-block;
position: relative;
}
#map-svg {
border-style: solid;
}
#map-svg img {
width: 70vh;
height: 80vh;
display: block;
}
#pog-outer {
position: absolute;
}
#pog-inner {
position: absolute;
left:-9px;
top:-9px;
}
<div id="inner-map">
<div id="pog-outer" style="top:58.794%;left:28.915%">
<div id="pog-inner">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="18" height="18">
<defs>
<radialGradient id="Shiny" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
<stop offset="0%" stop-color="#FFFFFF" />
<stop offset="50%" stop-color="#DD3333" />
<stop offset="75%" stop-color="#990000" />
<stop offset="100%" stop-color="#000000" />
</radialGradient>
</defs>
<circle r="6" cx="9" cy="9" fill="url(#Shiny)" />
</svg>
</div>
</div>
<div id="map-svg">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d5/North_America_laea_location_map.svg#svgView(preserveAspectRatio(xMidYMid slice))">
</div>
</div>
You can replace the height: 80vh; with height: 80% in the element and this way it's going to always hide the non-blue svg part and without making any overflow.
#inner-map {
display: inline-block;
position: relative;
}
#map-svg {
border-style: solid;
}
#map-svg img {
width: 100%;
height: 80%;
display: block;
}
#pog-outer {
position: absolute;
}
#pog-inner {
position: absolute;
left:-9px;
top:-9px;
}
<div id="inner-map">
<div id="pog-outer" style="top:58.794%;left:28.915%">
<div id="pog-inner">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="18" height="18">
<defs>
<radialGradient id="Shiny" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
<stop offset="0%" stop-color="#FFFFFF" />
<stop offset="50%" stop-color="#DD3333" />
<stop offset="75%" stop-color="#990000" />
<stop offset="100%" stop-color="#000000" />
</radialGradient>
</defs>
<circle r="6" cx="9" cy="9" fill="url(#Shiny)" />
</svg>
</div>
</div>
<div id="map-svg">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d5/North_America_laea_location_map.svg">
</div>
</div>

How to give the linear-gradient in svg as a background color for a div?

I have an svg like
<svg>
<linearGradient id="SVGID_124_" gradientUnits="userSpaceOnUse" x1="205.2935" y1="707.9475" x2="206.9863" y2="707.9475" gradientTransform="matrix(41.432 0 0 -41.432 -8114.9512 30139.9746)">
<stop offset="0" style="stop-color:#0071BC"/>
<stop offset="3.780070e-02" style="stop-color:#0071BC"/>
<stop offset="0.6151" style="stop-color:#00538B"/>
<stop offset="0.784" style="stop-color:#004C86"/>
<stop offset="0.9966" style="stop-color:#003B7C"/>
<stop offset="1" style="stop-color:#003B7C"/>
</linearGradient>
</svg>
I'm not sure how can I give this linear gradient as a background for a button. I tried the following, but I don't know how to give gradient transform in css.
.btn {
background: linear-gradient(to right, #0071BC 0%, #0071BC 37.80070%, #00538B 061.51%, #004C86 078.4%, #003B7C 099.66%, #003B7C 100%);
color: white;
border-radius: 8px;
/* border: 1px solid #00538B; */
width: 95%;
height: 25px;
padding: 0px;
}
<button class="btn">button</button>
Can somebody help?
It is expected to look like this
But i'm getting something like:
This is a close gradient in css.
.btn {
background: linear-gradient(to right, #0071bd 0%,#0171bb 39%,#016db5 41%,#005691 58%,#005691 59%,#01538b 61%,#014c86 78%,#003c7b 100%);
border-radius: 5px;
color: #fff;
border: none;
}
<button class="btn">Closed</button>
In generally, I'm using the gradient editor by colorzila to generate gradients from image / css / manually. May there are another tools.
You can use the SVG itself, BUT:
You have to make sure that the gradient's coordinates are right and feet to the element (aka .btn) which in this case, not.
You need to convert it to base64.
In the below snippet, for quick fixing, I created a script that read the svg in the html and convert it to base64 so you can tuning your gradient with it.
Also, I changed a little the SVG syntax, Take a look:
const svg = document.querySelector('svg').outerHTML;
const base64 = window.btoa(svg);
document.querySelector('.btn').style.backgroundImage = `url(data:image/svg+xml;base64,${base64})`;
.btn {
background: top repeat-x;
background-size: cover;
border-radius: 5px;
color: #fff;
border: none;
}
<button class="btn">Closed</button>
<svg width="1000px" height="30000px" xmlns="http://www.w3.org/2000/svg" style="display: none">
<linearGradient id="SVGID_124_" gradientUnits="userSpaceOnUse" x1="205.2935" y1="707.9475" x2="206.9863" y2="707.9475" gradientTransform="matrix(41.432 0 0 -41.432 -8114.9512 30139.9746)">
<stop offset="0" style="stop-color:#0071BC"/>
<stop offset="3.780070e-02" style="stop-color:#0071BC"/>
<stop offset="0.6151" style="stop-color:#00538B"/>
<stop offset="0.784" style="stop-color:#004C86"/>
<stop offset="0.9966" style="stop-color:#003B7C"/>
<stop offset="1" style="stop-color:#003B7C"/>
</linearGradient>
<g>
<rect fill="url(#SVGID_124_)" stroke-width="0" x="0" y="0" width="100%" height="100%" />
</g>
</svg>

SVG take up 400% of screensize

I'm trying to make my SVG take up 400% of the screen width and height so I can move it to change the gradient:
SVG
html, body {
margin:0;
padding:0;
overflow:hidden;
}
svg {
position:fixed;
top:0;
bottom:0;
left:0;
right:0;
height: 400%;
width: 400%;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="LinearGradient" x1="0%" y1="0%" x2="100%" y2="100%" spreadMethod="pad" gradientTransform="rotate(45)">
<stop offset="0%" stop-color="#00cc00" stop-opacity="1" />
<stop offset="100%" stop-color="#006600" stop-opacity="1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="100%" style="fill:url(#LinearGradient);" />
</svg>
However, this doesn't even fill it up 100% of the screen, yet alone 400%!
Just add your SVG CSS inside svg:not(:root). Check updated Snippet below
html, body {
margin:0;
padding:0;
height: 100%;
}
/*svg {
position:fixed;
top:0;
bottom:0;
left:0;
right:0;
height: 400%;
width: 400%;
}*/
svg:not(:root) {
width: 400%;
height: 400%;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="LinearGradient" x1="0%" y1="0%" x2="100%" y2="100%" spreadMethod="pad" gradientTransform="rotate(45)">
<stop offset="0%" stop-color="#00cc00" stop-opacity="1" />
<stop offset="100%" stop-color="#006600" stop-opacity="1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="100%" style="fill:url(#LinearGradient);" />
</svg>

Linear Gradient SVG 3 colors increase the width of the middle color

I have a linear gradient with the below code
<svg width="120" height="240" >
<linearGradient id="dsp" x1="0" x2="0" y1="0" y2="1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="50%"/>
<stop class="stop3" offset="100%"/>
</linearGradient>
<style type="text/css">
.stop1 { stop-color: red; }
.stop2 { stop-color: yellow; stop-opacity: 0.7; }
.stop3 { stop-color: green; }
</style>
Now I want to increase the height of the middle color that is the yellow color.
I tried to increase the offset value of yellow color but instead of increasing the width the color band shifts downwards.
I want that the red and green should contain only 10% of the height of the SVG in below format
Red >> 15%
yellow >> 70%
green >> 15%
This is the color distribution expected.
just add two more stops in between the start/end stop and the middle...
EDIT based on squeamish ossifrages comment
.stop1 { stop-color: red; }
.stop2 { stop-color: yellow; stop-opacity: 0.7; }
.stop3 { stop-color: green; }
<svg width="120" height="240" >
<linearGradient id="dsp" x1="0" x2="0" y1="0" y2="1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="20%"/>
<stop class="stop2" offset="80%"/>
<stop class="stop3" offset="100%"/>
</linearGradient>
<rect x="0" y="0" width="240" height="120" fill="url(#dsp)"/>
</svg>

On hover change SVG from colour to gradient with a transition

I have an SVG image which I would like to change from a block colour to a gradient. I have got this working, however I would like to have a transition or animation. Is this possible - if so how would it be achieved?
http://jsfiddle.net/otaxjpa2/
HTML:
<svg width="96px" height="96px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" fy="90%" >
<stop offset="0" style="stop-color:#1EBEE0"/>
<stop offset="1" style="stop-color:#952491"/>
<animate attributeName="fy"from="0" to="1" dur="5s" repeatCount="indefinite" />
</linearGradient>
</defs>
<path id="time-3-icon" d="M256,50C142.229,50,50,142.229,50,256c0,113.77,92.229,206,206,206c113.77,0,206-92.23,206-206
C462,142.229,369.77,50,256,50z M256,417c-88.977,0-161-72.008-161-161c0-88.979,72.008-161,161-161c88.977,0,161,72.007,161,161
C417,344.977,344.992,417,256,417z M382.816,265.785c1.711,0.297,2.961,1.781,2.961,3.518v0.093c0,1.72-1.223,3.188-2.914,3.505
c-37.093,6.938-124.97,21.35-134.613,21.35c-13.808,0-25-11.192-25-25c0-9.832,14.79-104.675,21.618-143.081
c0.274-1.542,1.615-2.669,3.181-2.669h0.008c1.709,0,3.164,1.243,3.431,2.932l18.933,119.904L382.816,265.785z"/>
</svg>
CSS:
svg {
fill: blue;
transition: all 0.3s ease;
display: inline-block;
-webkit-transition: fill .4s ease;
-moz-transition: fill .4s ease;
-o-transition: fill .4s ease;
transition: fill .4s ease;
}
svg:hover {
fill: url(#gradient);
}
Any pointers would be much appreciated!
You can avoid using two rects by transitioning the stop-colors instead:
svg {
display: inline-block;
}
stop {
transition: .4s ease;
}
/* Use the colors to transition to */
svg:hover stop:first-child {
stop-color: #1EBEE0;
}
svg:hover stop:last-child {
stop-color: #952491;
}
<svg width="96px" height="96px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" fy="90%">
<stop offset="0" stop-color="blue" /> <!-- Colors to transition from -->
<stop offset="1" stop-color="blue" />
</linearGradient>
<mask id="clock-icon-mask" maskUnits="userSpaceOnUse" x="0" y="0" width="512" height="512">
<path d="M256,50C142.229,50,50,142.229,50,256c0,113.77,92.229,206,206,206c113.77,0,206-92.23,206-206C462,142.229,369.77,50,256,50z M256,417c-88.977,0-161-72.008-161-161c0-88.979,72.008-161,161-161c88.977,0,161,72.007,161,161C417,344.977,344.992,417,256,417z M382.816,265.785c1.711,0.297,2.961,1.781,2.961,3.518v0.093c0,1.72-1.223,3.188-2.914,3.505c-37.093,6.938-124.97,21.35-134.613,21.35c-13.808,0-25-11.192-25-25c0-9.832,14.79-104.675,21.618-143.081c0.274-1.542,1.615-2.669,3.181-2.669h0.008c1.709,0,3.164,1.243,3.431,2.932l18.933,119.904L382.816,265.785z"
fill="white" />
</mask>
</defs>
<g mask="url(#clock-icon-mask)">
<rect x="0" y="0" width="512" height="512" fill="url(#gradient)" />
</g>
</svg>
Here's a demo of the technique using a simplified shape (no mask required).
Put the two fill styles on overlapping <rect> objects, and use the clock icon as a mask object applied to both <rect> objects. You can then animate the apparent fill style by animating the opacity of the uppermost <rect>. Remember to apply a white fill to the mask object (white=opaque, black=transparent).
If the following snippet doesn't work, try this jsfiddle link.
#clock-gradient {
opacity: 0.0;
display: inline-block;
-webkit-transition: opacity .4s ease;
-moz-transition: opacity .4s ease;
-o-transition: opacity .4s ease;
transition: opacity .4s ease;
}
#clock-gradient:hover {
opacity: 1.0;
}
<svg width="96px" height="96px" viewBox="0 0 512 512" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" fy="90%">
<stop offset="0" style="stop-color:#1EBEE0" />
<stop offset="1" style="stop-color:#952491" />
</linearGradient>
<mask id="clock-icon-mask" maskUnits="userSpaceOnUse" x="0" y="0" width="512" height="512">
<path d="M256,50C142.229,50,50,142.229,50,256c0,113.77,92.229,206,206,206c113.77,0,206-92.23,206-206C462,142.229,369.77,50,256,50z M256,417c-88.977,0-161-72.008-161-161c0-88.979,72.008-161,161-161c88.977,0,161,72.007,161,161C417,344.977,344.992,417,256,417z M382.816,265.785c1.711,0.297,2.961,1.781,2.961,3.518v0.093c0,1.72-1.223,3.188-2.914,3.505c-37.093,6.938-124.97,21.35-134.613,21.35c-13.808,0-25-11.192-25-25c0-9.832,14.79-104.675,21.618-143.081c0.274-1.542,1.615-2.669,3.181-2.669h0.008c1.709,0,3.164,1.243,3.431,2.932l18.933,119.904L382.816,265.785z" fill="white" />
</mask>
</defs>
<g mask="url(#clock-icon-mask)">
<rect x="0" y="0" width="512" height="512" fill="blue" />
<rect id="clock-gradient" x="0" y="0" width="512" height="512" fill="url(#gradient)" />
</g>
</svg>