SVG line cross animation for icons - css

I have two icons, one in original state, one in crossed off state.
I want to animate the cross line but changing dash-offset is not useful since those are two different svgs.
I'm looking at these animated icons but still couldn't figure out the magic part. I want to ask:
what should be the transition work flow?
I prefer to use pure CSS, is it possible?
A working example would be appreciated.

The animated icons on that page are quite complicated (more that they need to be IMO). But basically what they are doing is sliding a rectangular mask in from right to left, that covers the first icon, and uncovers the second icon.
Here is a simplified version, using pure CSS, that hopefully makes it clearer.
svg {
width: 100px;
height: 100px;
}
/* slides the two masks to the left on hover */
svg:hover #bottom-rect,
svg:hover #top-rect
{
transition: transform 500ms;
transform: translate(-24px, 0px);
}
/* slides the two masks back to the right when not hovered */
svg #bottom-rect,
svg #top-rect {
transition: transform 500ms;
transform: translate(0px, 0px);
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<defs>
<mask id="bottom">
<rect id="bottom-rect" width="24" height="24" fill="white" stroke="none"/>
</mask>
<mask id="top">
<rect id="top-rect" x="24" width="24" height="24" fill="white" stroke="none"/>
</mask>
</defs>
<g mask="url(#bottom)">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
<g mask="url(#top)">
<line x1="1" y1="1" x2="23" y2="23"></line>
<path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path>
<path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
</svg>

An approach with CSS.
You just show/hide the icons you want on hover. To animate the line, use CSS animations with stroke-dasharray and stroke-dashoffset. Comments in code.
/* for demo */
svg {
width: 100px;
height: 100px;
border: 1px solid black;
}
/* hide the off icon */
svg .off {
opacity: 0;
}
/* when user hovers SVG, the on icon is hidden... */
svg:hover .on {
opacity: 0;
}
/* ... and the off icon is shown */
svg:hover .off {
opacity: 1;
}
/* initial values for the stroke
-- these can be obtained with JS,
-- or you can work them out manually for CSS
*/
svg .line {
stroke-dashoffset: 40px;
stroke-dasharray: 40px;
}
/* when user hovers SVG, animate the line */
svg:hover .line {
animation: addLine 800ms forwards;
}
/* values for line animation */
#keyframes addLine {
from {
stroke-dashoffset: 40px;
}
to {
stroke-dashoffset: 0;
}
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<g class="on">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
<g class="off">
<line class="line" x1="1" y1="1" x2="23" y2="23"></line>
<path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path>
<path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
</svg>

Related

svg: styling a path within <use>

I'm trying to use CSS to style the fill of a specific <path> within a <symbol>. I've assigned fill:inherit to the path in the symbol <defs> and I can query the <use> instances of the symbol within the SVG DOM, but I can't seem to access that path within these instances. I looked into inherit for the CSS and currentColor for the fill of the <path> but no luck. Any help is appreciated.
<svg>
<defs>
<style>
symbol#DateCard path.purple {
fill:inherit;
}
use[*|href="#DateCard"] path.purple{
fill:#ff0095;
transition:fill .6s;
}
use[*|href="#DateCard"] path.purple:hover{
path:#ff0000;
}
</style>
<symbol id="DateCard">
<path class="purple" fill="currentColor" d="..."/>
</symbol>
</defs>
<use xlink:href="#DateCard"/>
<svg>
I can query the path within symbol, but when I query the specific paths within a <use> instance, this returns an empty NodeList:
document.querySelectorAll('use[*|href="#DateCard"] path.purple')
Styling inside the shadow DOM needs to be done inside the shadow DOM.
What I learned from Styling SVG Content with CSS | Codrops is that CSS variables are very useful in this case. So, here I created different ways of styling: using a style attribute and style element inside the symbol in combination with CSS variables from the "outside" of the symbol.
.card1 {
--path1-color: #0099CC;
--path2-color: #FFDF34;
}
.card2 {
--path1-color: #00008B;
--path2-color: #FF8C00;
}
.card2:hover {
--path1-color: #00BFFF;
}
<svg viewBox="0 0 200 100" width="400">
<defs>
<symbol id="DateCard">
<style>
.path2 {
fill: var(--path2-color);
transition: fill 1s;
}
.path2:hover {
fill: #800000;
}
</style>
<path class="path1" style="fill: var(--path1-color);transition: fill .6s;" d="M20 40 a 20 20 0 1 1 1 0"/>
<path class="path2" d="M40 60 a 20 20 0 1 1 1 0"/>
</symbol>
</defs>
<use href="#DateCard" class="card1"/>
<use href="#DateCard" class="card2" transform="translate(80 0)"/>
<svg>
Update
OP ask if the hover effect can be achieved using attributes in SVG. An alternative to the :hover pseudo class would be an animation started by the mouse entering and leaving the animated element. Unfortunately it is not as flexible as CSS -- it is difficult to style <animate>.
Here is an example on animating the second <path> in the symbol:
.card1 {
--path1-color: #0099CC;
--path2-color: #FFDF34;
}
.card2 {
--path1-color: #00008B;
--path2-color: #FF8C00;
}
.card2:hover {
--path1-color: #00BFFF;
}
<svg viewBox="0 0 200 100" width="400">
<defs>
<symbol id="DateCard">
<style>
.path2 {
fill: var(--path2-color);
}
</style>
<path class="path1" style="fill: var(--path1-color);transition: fill .6s;" d="M20 40 a 20 20 0 1 1 1 0"/>
<path class="path2" d="M40 60 a 20 20 0 1 1 1 0">
<animate attributeName="fill" dur="1s" values="#FF8C00;#800000" begin="mouseenter" fill="freeze" />
<animate attributeName="fill" dur="1s" from="#800000" to="#FF8C00" begin="mouseleave" fill="freeze" />
</path>
</symbol>
</defs>
<use href="#DateCard" class="card1"/>
<use href="#DateCard" class="card2" transform="translate(80 0)"/>
<svg>

CSS SVG align vertical middle with Label

Hi I have the following code where I need to vertical align the SVG with the label.
g {
fill: blue;
fill-rule: evenodd;
}
#firstdiv:hover {
border-radius: 25px;
background: #dcd9d9;
padding-top: 6px;
height: 35px;
width: 100%;
display: inline-block;
}
#svgcontainer {
display: inline;
}
<div id='firstdiv'>
<div id='svgcontainer'>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22" height="22" viewBox="0 0 22 22">
<defs>
<path id="a" d="M11 11a3.666 3.666 0 0 0 3.667-3.667A3.666 3.666 0 0 0 11 3.667a3.666 3.666 0 0 0-3.667 3.666A3.666 3.666 0 0 0 11 11zm0 1.833c-2.447 0-7.333 1.229-7.333 3.667v1.833h14.666V16.5c0-2.438-4.885-3.667-7.333-3.667z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="b" fill="#fff">
<use xlink:href="#a"/>
</mask>
<g fill="#000" fill-opacity=".54" mask="url(#b)">
<path d="M0 0h22v22H0z"/>
</g>
</g>
</svg>
</div>
Test
</div>
And when you hover nothing has to moved because right now when hover because the SVG is not vertically aligned to the middle when hover there is a move of the elements.
https://jsfiddle.net/164seo3g/1/
Thanks
Few pointers,
usually hover should change only the relevant css properties, it should not change layout & stuff, so, what I did is to split styles, without hover contains all the props that related to layout, hover, contains only the change.
You can use vertical-align: middle on item that has siblings, your svg was inside a container, and therefore this wasn't worked.
g {
fill: blue;
fill-rule: evenodd;
}
#firstdiv {
border-radius: 25px;
line-height: 35px;
width: 100%;
display: inline-block;
}
#firstdiv:hover {
background: #dcd9d9;
}
#svgcontainer {
display: inline-block;
vertical-align: middle;
}
<div id='firstdiv'>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22" height="22" viewBox="0 0 22 22" id='svgcontainer'>
<defs>
<path id="a" d="M11 11a3.666 3.666 0 0 0 3.667-3.667A3.666 3.666 0 0 0 11 3.667a3.666 3.666 0 0 0-3.667 3.666A3.666 3.666 0 0 0 11 11zm0 1.833c-2.447 0-7.333 1.229-7.333 3.667v1.833h14.666V16.5c0-2.438-4.885-3.667-7.333-3.667z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="b" fill="#fff">
<use xlink:href="#a"/>
</mask>
<g fill="#000" fill-opacity=".54" mask="url(#b)">
<path d="M0 0h22v22H0z"/>
</g>
</g>
</svg> Test
</div>

Animating SVG with CSS

I have a simple line SVG that is animating correctly. The problem is that on first load the SVG paths show and then disappear prior to the start.I have tried setting opacity on st1 and st2 to 0 and then keyframes to to opacity 1. This kind of works, but the SVG then disappears after it is run.
Am I missing something simple?
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 485 500.9" style="enable-background:new 0 0 485 500.9;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;}
.st1{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;animation-delay: 1s;}
.st2{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;animation-delay: 3s;}
#keyframes draw {
from {
stroke-dashoffset: -1000;
}
to {
stroke-dashoffset: 0;
}
}
</style>
<g>
<defs>
<rect id="SVGID_1_" x="-0.1" y="0" width="485" height="501"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path class="st0" d="M0.4,97.4c0-14.2,14.2-14.2,14.2-14.2H100l5.1,0h86.3c0,0,14.2,0,14.2-14.2V36.4V0"/>
<path class="st1" d="M207.5,236.3l0-31.3c0,0,0-14.2-14.2-14.2h-15.1l-142.8,0.1H14.6c-14.2,0-14.2-14.2-14.2-14.2V103"/>
<path class="st2" d="M484.9,500.5H221.8c-14.2,0-14.2-14.2-14.2-14.2l-0.1-242.6"/>
</g>
</svg>
See:
https://jsfiddle.net/suLkr4po/
How do I restructure this so each path comes in after the other has finished from top to bottom?
Add animation-fill-mode: backwards to the style of the animated elements. That will apply the start value before the animation is started.

SVG sprite on stack don't appear on Safarii

I created SVG sprite, where icons are on stack and displayed when targeting chosen ID. It works ok, but I don't know why, icons not appear on Safari, I can't find explanation in case when you're using SVG as a background. Is any one familiar with this problem?
SVG
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="icon" class="icon" version="1.1">
<defs>
<style>
svg .icon {
display: none;
}
svg .icon:target {
display: inline-block;
}
</style>
</defs>
<svg viewBox="0 0 24 24">
<g id="icon-instagram" class="icon" fill="#fff">
<path fill-rule="nonzero"
d="M17.2808471,0 L6.58644706,0 C2.95468235,0 0,2.95482353 0,6.58658824 L0,17.2809882 C0,20.9128941 2.95468235,23.8675765 6.58644706,23.8675765 L17.2808471,23.8675765 C20.9128941,23.8675765 23.8675765,20.9127529 23.8675765,17.2809882 L23.8675765,6.58658824 C23.8677176,2.95482353 20.9128941,0 17.2808471,0 Z M21.7500706,17.2809882 C21.7500706,19.7452235 19.7452235,21.7499294 17.2809882,21.7499294 L6.58644706,21.7499294 C4.12235294,21.7500706 2.11764706,19.7452235 2.11764706,17.2809882 L2.11764706,6.58658824 C2.11764706,4.12249412 4.12235294,2.11764706 6.58644706,2.11764706 L17.2808471,2.11764706 C19.7450824,2.11764706 21.7499294,4.12249412 21.7499294,6.58658824 L21.7499294,17.2809882 L21.7500706,17.2809882 Z"/>
<path fill-rule="nonzero"
d="M11.9337882 5.784C8.54258824 5.784 5.78371765 8.54287059 5.78371765 11.9340706 5.78371765 15.3251294 8.54258824 18.0838588 11.9337882 18.0838588 15.3249882 18.0838588 18.0838588 15.3251294 18.0838588 11.9340706 18.0838588 8.54287059 15.3249882 5.784 11.9337882 5.784zM11.9337882 15.9660706C9.7104 15.9660706 7.90136471 14.1573176 7.90136471 11.9339294 7.90136471 9.7104 9.71025882 7.90150588 11.9337882 7.90150588 14.1573176 7.90150588 15.9662118 9.7104 15.9662118 11.9339294 15.9662118 14.1573176 14.1571765 15.9660706 11.9337882 15.9660706zM18.3417882 3.98837647C17.9337882 3.98837647 17.5329882 4.15355294 17.2448471 4.44296471 16.9552941 4.73096471 16.7888471 5.13190588 16.7888471 5.54131765 16.7888471 5.94945882 16.9554353 6.35025882 17.2448471 6.63967059 17.5328471 6.92767059 17.9337882 7.09425882 18.3417882 7.09425882 18.7512 7.09425882 19.1507294 6.92767059 19.4401412 6.63967059 19.7295529 6.35025882 19.8947294 5.94931765 19.8947294 5.54131765 19.8947294 5.13190588 19.7295529 4.73096471 19.4401412 4.44296471 19.1521412 4.15355294 18.7512 3.98837647 18.3417882 3.98837647z"/>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="icon-facebook" class="icon" fill="#fff">
<path d="M2.93630055,4.93539414 L2.93630055,8.17223941 L0.564884222,8.17223941 L0.564884222,12.1302664 L2.93630055,12.1302664 L2.93630055,23.8921306 L7.80769311,23.8921306 L7.80769311,12.1305943 L11.0766237,12.1305943 C11.0766237,12.1305943 11.3827734,10.2327507 11.5311748,8.15764524 L7.82611347,8.15764524 L7.82611347,5.45138285 C7.82611347,5.04690017 8.35724295,4.50281631 8.88219587,4.50281631 L11.5363128,4.50281631 L11.5363128,0.382285714 L7.92761676,0.382285714 C2.81588497,0.382012415 2.93630055,4.34397487 2.93630055,4.93539414 Z"/>
</g>
</svg>
CSS
.icon-instagram {
width: 24px;
height: 24px;
background: url("../svg/viva-sprite.svg#icon-instagram") no-repeat;
}
.icon-facebook {
width: 24px;
height: 24px;
background: url("../svg/viva-sprite.svg#icon-facebook") no-repeat;
}

SVG mix-blend-mode not showing in firefox

Testing an svg using mix-blend-mode: multiply in Firefox 44 and it will not apply the blend-mode at all. But on another page I have a similar SVG and it shows fine. So it seems like the problem is with the SVG code itself...
I've seen a few other people having similar issues and have looked at all the proposed solutions, none of which worked for me. (adding background-color to div, adding a transparent border)
HTML:
<div class="about-background clearfix">
<object class="willItBlend" data="../svg/about-bg.svg" type="image/svg+xml"></object>
<img class="blender" src="../svg/about-bg.png" />
</div>
CSS (png fallback):
#supports not(mix-blend-mode: multiply) {
.blender {
display: block;
}
.willItBlend {
display: none;
}
SVG:
<svg width="489" height="441" viewBox="0 0 489 441" xmlns="http://www.w3.org/2000/svg">
<title>
about-bg
</title>
<style>
path { mix-blend-mode: multiply; }
ellipse { mix-blend-mode: multiply; }
</style>
<g fill="none" fill-rule="evenodd">
<g transform="translate(-236.973 -308)" stroke-width="33.6">
<ellipse stroke="#E2E42E" cx="345.986" cy="357.28" rx="345.986" ry="357.28"/>
<ellipse stroke="#ED1F71" cx="346.972" cy="358.298" rx="295.715" ry="305.368"/>
<ellipse stroke="#03A8DE" cx="346.972" cy="358.298" rx="244.458" ry="252.437"/>
</g>
<g transform="translate(-284 -294.56)">
<path d="M345.986 714.56c191.083 0 345.987-159.96 345.987-357.28C691.973 159.96 537.07 0 345.986 0 154.903 0 0 159.96 0 357.28 0 554.6 154.903 714.56 345.986 714.56z" stroke="#E2E42E" stroke-width="11.2"/>
<ellipse stroke="#ED1F71" stroke-width="22.4" cx="346.972" cy="358.298" rx="295.715" ry="305.368"/>
<ellipse stroke="#03A8DE" stroke-width="22.4" cx="346.972" cy="358.298" rx="244.458" ry="252.437"/>
</g>
<g transform="translate(-138.44 -164.64)">
<path d="M247.453 510.72c136.665 0 247.453-114.33 247.453-255.36C494.906 114.33 384.118 0 247.453 0 110.788 0 0 114.33 0 255.36c0 141.03 110.788 255.36 247.453 255.36z" stroke="#E2E42E" stroke-width="11.2"/>
<ellipse stroke="#ED1F71" stroke-width="5.6" cx="248.573" cy="256.48" rx="211.623" ry="218.4"/>
<ellipse stroke="#03A8DE" stroke-width="5.6" cx="247.453" cy="256.48" rx="174.673" ry="180.32"/>
</g>
</g>
</svg>

Resources