Home > Back-end >  CSS only animation - how to fill that svg heart-icon?
CSS only animation - how to fill that svg heart-icon?

Time:07-28

I'm struggling with CSS transitions and animations.

the goal of my task is simple :

  • to have a "heart" icon that users can click on and have it filled in red (it is required for the heart to fill slowly);

  • Ideally, users can click again on the "filled heart" to empty it (the like and unlike mechanic);

  • Oh and one last requirement : only html and css/scss allowed on board.

I had trouble first to make the heart-icon. I checked the web for various solutions, from designing it myself in code-lines to importing an image. Finally, I decided to import a .svg file from this site and with this code:

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 40.508 40.508" style="enable-background:new 0 0 40.508 40.508;" xml:space="preserve">
<g>
    <path style="fill:#010002;" d="M3.023,20.822c0.019,0.031,0.042,0.059,0.066,0.083l15.918,16.914
        c0.115,0.122,0.271,0.192,0.444,0.197h0.012c0.163,0,0.317-0.062,0.435-0.176L37.28,21.032c0.008-0.006,0.076-0.068,0.117-0.108
        c0.034-0.032,0.062-0.065,0.068-0.081c1.962-2.032,3.043-4.702,3.043-7.517c0-5.974-4.86-10.834-10.835-10.834
        c-3.91,0-7.498,2.094-9.419,5.48c-1.92-3.387-5.508-5.48-9.419-5.48C4.86,2.492,0,7.352,0,13.326
        C-0.001,16.14,1.078,18.808,3.023,20.822z M10.834,3.743c3.875,0,7.346,2.312,8.842,5.891c0.098,0.233,0.324,0.383,0.577,0.383
        c0.252,0,0.479-0.15,0.577-0.384c1.497-3.578,4.968-5.89,8.843-5.89c5.285,0,9.585,4.3,9.585,9.584
        c0,2.521-0.978,4.904-2.754,6.712c-0.017,0.018-0.032,0.035-0.045,0.053L19.483,36.5l-15.4-16.358
        c-0.023-0.037-0.05-0.072-0.082-0.104c-1.775-1.805-2.752-4.188-2.752-6.711C1.249,8.042,5.549,3.743,10.834,3.743z"/>
</g>
</svg>

With no idea how to work properly with an SVG, I searched the web, looked-up some articles and YouTube videos, the course I'm taking right now is not telling me much or not in an intuitive way but I finally put my hands on two interesting-looking opportunities :

1] this heart animation found on Codepen


Its pro : it's already made. its nearly and honestly, the few Js code for the "pulse" effect is not needed in my own case, so I deleted it.

It's cons :

  • I can't figure out how to have the full heart to stay full. I know with an animation, you would have to insert something like :
 animation:forwards;

But here in this case, it doesn't seem to work if anyone has a solution, I think it would be a good option for the project they asked me to provide;

it doesn't use '@keyframes', and looks like a simple transition, but, again, my lack of knowledge makes it difficult to interpret;

  • The "filling" animation would be better if it simulated a "loading bar" starting from the bottom. But honestly it's more a cosmetic element rather than a real problem;

2] the "water filling effect" question found here


The linked Q/A was related to a water-filling animation applied to a circle.

its pro: it's a good effect and the additional animations proposed by another contributor are brilliant too ! I prefer this "bottom-up" filling effect than the one in the first option.

its con: Well it's not a proper con, it's me not being able to adapt it to my own needs. in the present example, I can't apply it to my .svg image rather than a "natively made form" like they did with their circle.

I had hoped to take the animation described in the post and apply it to my heart-icon. Well, needless to say that, without proper skills in the field, I merely copied/pasted what seemed to work and surprisingly, it has some effect but not the one I'm looking for, here's my current code.

[EDIT : I use here ":hover" instead of ":active" because I couldn't find how to simply click once on the heart in order for it to fill automatically, with ":active" I have to click on itmultiple times like in a button-smashing mini-game to fill it.]

HTML first :

<body>
    <div >
      <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
        viewBox="0 0 40.508 40.508" style="enable-background:new 0 0 40.508 40.508;" xml:space="preserve">
        <g>
          <path style="fill:#010002;" d="M3.023,20.822c0.019,0.031,0.042,0.059,0.066,0.083l15.918,16.914
          c0.115,0.122,0.271,0.192,0.444,0.197h0.012c0.163,0,0.317-0.062,0.435-0.176L37.28,21.032c0.008-0.006,0.076-0.068,0.117-0.108
          c0.034-0.032,0.062-0.065,0.068-0.081c1.962-2.032,3.043-4.702,3.043-7.517c0-5.974-4.86-10.834-10.835-10.834
          c-3.91,0-7.498,2.094-9.419,5.48c-1.92-3.387-5.508-5.48-9.419-5.48C4.86,2.492,0,7.352,0,13.326
          C-0.001,16.14,1.078,18.808,3.023,20.822z M10.834,3.743c3.875,0,7.346,2.312,8.842,5.891c0.098,0.233,0.324,0.383,0.577,0.383
          c0.252,0,0.479-0.15,0.577-0.384c1.497-3.578,4.968-5.89,8.843-5.89c5.285,0,9.585,4.3,9.585,9.584
          c0,2.521-0.978,4.904-2.754,6.712c-0.017,0.018-0.032,0.035-0.045,0.053L19.483,36.5l-15.4-16.358
          c-0.023-0.037-0.05-0.072-0.082-0.104c-1.775-1.805-2.752-4.188-2.752-6.711C1.249,8.042,5.549,3.743,10.834,3.743z"/>
        </g>
      </svg>
    </div>
  </body>

And then the CSS :

      .heart{
        width:40px;
        position:relative;
        
        overflow:hidden;
      }

      .heart:hover:before{
        content:'';
        position:absolute;
        background: #04ACFF;
        z-index: -1;
        width:100%;
        bottom:0;
        animation: wipe 5s forwards;

      }

      @keyframes wipe {
  0% {
    height: 0;
  }
  100% {
    height: 100%;
  }
}

If we refer to the original code I found, I decided to delete the "background: #000" and had to add a "z-index:-1" in order to have the filling animation not overlapping over the borders of the icon. But then I'm stuck and after trying to mess around and rereading what I had at hand, I decided to type this (long) post.

I would like to thank you if you've been this far, thanks for reading my request today and thank you in advance for any advice and solution you will be kind to share with me,

Regards,

Elrad.

CodePudding user response:

I think the solution would be something like this: It still is a simple transition for the filling of the heart and an animation for the wave-effect.

it uses custom properties that you can play around with

:root {
   --stroke-width: 2px;
   --heart-width: 150px;
   --transition-length: 1.2s;
   --heart-color: #d32f2f;
}

.heart-container {
   position: relative;
   width: var(--heart-width, 100px);
   aspect-ratio: 1/1;
   overflow: hidden;
   clip-path: url(#svgClip);
}

.heart-clip {
   appearance: none;
   margin: 0px;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
   position: absolute;
   overflow: hidden;
   z-index: 2;
}

.heart-clip   .fill {
   top:0;
   left:0;
   transform: translateY(50%);
   width: calc(2 * var(--heart-width, 100px));
   aspect-ratio: 1/1;
   transition: transform var(--transition-length, 0s) cubic-bezier(.2, .6, .8, .4);
}
  
.heart-clip:checked   .fill {
   transform: translateY(0);
}

.heart-stroke {
   width: calc(100% - (2 * var(--stroke-width, 2px)));
   aspect-ratio: 1/1;
   position: absolute;
   top: var(--stroke-width, 0);
   left: var(--stroke-width, 0);
   fill: transparent;;
   stroke: var(--heart-color);
   stroke-width: var(--stroke-width, 1px);
}

#waveShape {
   animation-name: waveAction;
   animation-iteration-count: infinite;
   animation-timing-function: linear;
   animation-duration: 1s;
   fill: var(--heart-color);
}

@keyframes waveAction {
   0% {
      transform: translate(-175px, 0px);
   }
   100% {
      transform: translate(0px, 0px);
   }
}
<svg id='bigHeart' height="0" width="0">
    <defs>
       <clipPath id=svgClip clipPathUnits="objectBoundingBox" transform="scale(0.01 0.01)">
         <path d='M10,30 A20,20,0,0,1,50,30 A20,20,0,0,1,90,30 Q90,60,50,90 Q10,60,10,30 Z'>     
       </clipPath>
    </defs>
</svg>

<div >
   <svg viewBox="0 0 100 100" class='heart-stroke'>
      <path id=bigHeart d="M10,30 A20,20,0,0,1,50,30 A20,20,0,0,1,90,30 Q90,60,50,90 Q10,60,10,30 Z" />    
   </svg>
  
   <input type='checkbox' class='heart-clip'>
   <div >
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 400 400" xml:space="preserve">
       <path d="M0,6c100,10,100,-10,200,0c100,10,100,-10,200,0v394,h-400Z" id="waveShape"></path>
    </svg>
   </div>
</div>

  • Related