【问题标题】:CSS only animation - how to fill that svg heart-icon?仅 CSS 动画 - 如何填充 svg 心形图标?
【发布时间】:2022-08-22 21:58:00
【问题描述】:

(这解决方案W3 验证器的 clean 可以在这篇文章的底部找到)

我的任务目标很简单:

  • 有一个“心脏”图标,用户可以点击并填充红色(需要心脏慢慢填充);

  • 理想情况下,用户可以再次点击“填满的心”来清空它(喜欢和不喜欢的机制);

  • 哦,最后一个要求:船上只允许使用 html 和 css/scss。

我第一次制作心形图标时遇到了麻烦。我在网上查看了各种解决方案,从自己在代码行中设计到导入图像。最后,我决定[从这个站点][1] 导入一个 .svg 文件,并使用以下代码:

<?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>

在不知道如何正确使用 SVG 的情况下,我搜索了网络,查找了一些文章和 YouTube 视频,我现在正在学习的课程并没有以直观的方式告诉我太多或没有,但我终于把我的抓住两个有趣的机会:

1] [在 Codepen 上找到的这个心脏动画][2]


它的专业: 已经做好了。老实说,在我自己的情况下,不需要用于“脉冲”效果的少数 Js 代码,因此我将其删除。

这是缺点

  • 我不知道如何拥有一颗饱满的心来保持饱满。我知道动画,你必须插入类似的东西:
 animation:forwards;

但是在这种情况下,如果有人有解决方案似乎不起作用,我认为这对于他们要求我提供的项目来说是一个不错的选择;

它不使用 \'@keyframes\',看起来像一个简单的过渡,但是,再次,我缺乏知识使其难以解释;

  • “填充”动画如果模拟一个从底部开始的“加载条”会更好。但老实说,这更像是一个装饰元素,而不是一个真正的问题;

2] [这里][3]找到的“补水效果”问题


链接的 Q/A 与应用于圆圈的注水动画有关。

它的专业: 效果不错,另外一个贡献者提出的附加动画也很棒!我更喜欢这种“自下而上”的填充效果,而不是第一个选项中的填充效果。

它的骗局: 嗯,这不是一个适当的骗局,是我无法适应我自己的需要。在本示例中,我不能将其应用于我的 .svg 图像,而不是像他们对圆圈所做的那样的“本地制作形式”。

我曾希望将帖子中描述的动画应用到我的心形图标上。好吧,不用说,在该领域没有适当的技能,我只是复制/粘贴似乎有效的东西,令人惊讶的是,它有一些效果,但不是我正在寻找的,这是我当前的代码。

[编辑:我在这里使用 \":hover\" 而不是 \":active\" 因为我找不到如何简单地单击心脏以使其自动填充,而使用 \":active\" 我有像在按钮粉碎迷你游戏中一样多次单击它来填充它。]

HTML第一:

<svg class=\'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\'></path>   
                                     </clipPath>
                                </defs>
                            </svg>
                            <div class=\"heart-container\">
                                <svg viewBox=\"0 0 100 100\" class=\'heart-stroke\'>
                                        <path class=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 class=\"fill\">
                                    <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,0v394h-400Z\" class=\"waveShape\"></path>
                                    </svg>
                                </div>
                            </div>

然后是 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%;
  }
}

如果我们参考[我找到的原始代码][3],我决定删除 \"background:#000\" 并添加一个 \"z-index:-1\" 以便有填充动画不重叠图标的边框。但后来我被卡住了,在试图搞砸并重新阅读我手头的东西之后,我决定输入这个(长)帖子。

如果您到目前为止,我要感谢您,感谢您今天阅读我的请求,并提前感谢您提供任何建议和解决方案,您将很乐意与我分享,

3] 解决方案(感谢@thehujib)

解决方案由@thehujib 在下面提供,我只在这里再次发布他的代码,因为它清除了 W3 验证器发现的所有小元素(主要是开放式和重复出现的 ID):

                        <svg class=\'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\'></path>   
                                     </clipPath>
                                </defs>
                                <linearGradient id=\"my-cool-gradient\" x2=\"1\" y2=\"1\">
                                    <stop offset=\"0%\" stop-color=\"#FF79DA\" />
                                    <stop offset=\"100%\" stop-color=\"#9356DC\" />
                                </linearGradient>
                            </svg>
                            <div class=\"heart-container\">
                                <svg viewBox=\"0 0 100 100\" class=\'heart-stroke\'>
                                        <path class=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 class=\"fill\">
                                    <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,0v394h-400Z\" class=\"waveShape\"></path>
                                    </svg>
                                </div>
                            </div>

和 CSS(唯一的变化是将一些重复的 ID 转换为 CLASSES :

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

.heart-container {
  position: relative;
  width:10%;
  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);
  }
}
``
Regards,

Elrad.


  [1]: https://www.svgrepo.com/svg/5233/heart
  [2]: https://codepen.io/GeorgeWL/pen/yLeGGMw
  [3]: https://stackoverflow.com/questions/29738787/filling-water-animation/29739227#29739227

    标签: css animation svg


    【解决方案1】:

    我认为解决方案是这样的: 依旧是一个简单的过渡,让内心的充实 和波浪效果的动画。

    它使用您可以使用的自定义属性

    :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 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 class="heart-container">
       <svg viewBox="0 0 100 100" class='heart-stroke'>
          <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" />    
       </svg>
      
       <input type='checkbox' class='heart-clip'>
       <div class="fill">
        <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,0v394h-400Z" class="waveShape"></path>
        </svg>
       </div>
    </div>

    【讨论】:

    • 谢谢 !感谢您抽出宝贵时间回答我,我会检查您的代码以确保我已完全理解所有内容 :-)
    • @thehujib 谢谢,除了在 Firefox 上,代码运行良好,如果你用上述浏览器尝试,你会看到一个“小故障”,动画不会在左下角停止。不过,Chrome 并没有受到该错误的影响。
    • 看起来动画 svg 形状不正确,我可能以某种方式弄乱了 waveShape 上的路径。
    • 是的,我输入了一对多的逗号,修复了它,所以它现在应该可以工作了
    • @thehujib - 1 感谢您的快速回答,它解决了我的 Firefox 兼容性问题。 2 - 您的 html 遇到了一些我设法修复的小问题,如果一切正常,我将在我的 OP 中发布更正的代码供您检查并更新您自己的答案!
    猜你喜欢
    • 2020-10-14
    • 2013-01-23
    • 2014-09-26
    • 2016-05-24
    • 2021-10-20
    • 2017-08-30
    • 2017-04-20
    • 2016-05-13
    • 2021-12-23
    相关资源
    最近更新 更多