Alexandr_TT Asked:2020-03-12 01:06:06 +0000 UTC2020-03-12 01:06:06 +0000 UTC 2020-03-12 01:06:06 +0000 UTC 如何制作图标动画 - 破碎的心 772 我有两个心形图标——完整的和破碎的。 有必要制作图标从一种状态到另一种状态的过渡动画。 从图中可以看出,动画被简化为心脏的一半相对于另一半围绕一个共同点旋转。 单击图标时需要开始动画。 javascript 2 个回答 Voted Alexandr_TT 2020-03-12T01:06:06Z2020-03-12T01:06:06Z 要实现动画,您需要绘制一条断层线和两半图标。 我们获取第一个图标并将其加载到矢量编辑器中。 使用工具 - 绘制贝塞尔曲线和直线 - 画断线 使用相同的工具,我们画出心脏左半边的轮廓,然后再次画出轮廓,但画出心脏的右半边。每次我们使轮廓闭合。 将文件保存Heart.svg在矢量编辑器中 从文件中复制心脏左右两半的补丁。 下面是右半部分的示例 <svg id="heart" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="200" viewBox="0 0 100 100"> <style> #right-half{ fill:#dc143c; } </style> <g> <path id="right-half" d="M63.9 24C58.5 24 53.5 27 50.2 32.5 49.8 35.3 50.5 40.6 50.5 40.6L48.8 45.2 53.8 49.7 47.6 55.5 54 57.8 49.8 61.6C49.7 69.1 50.2 69 50.1 75.4 50.1 75.4 50.2 75.7 50.2 75.7 50.6 75.7 51 75.5 51.1 75.1 53 70.1 58 66.3 63.4 62.2 70.9 56.5 78.6 50.7 79.2 41.1 79.4 36.4 77.9 32 74.8 28.8 73.5 27.4 72 26.3 70.4 25.5 68.4 24.5 66.1 24 63.9 24z"/> </g> </svg> 图标的左半部分 <svg id="heart" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="200" viewBox="0 0 100 100"> <style> #left-half{ fill:#dc143c; } </style> <g > <path id="left-half" d="m50.1 75.4c0 0 0.1 0.3 0.1 0.3-0.4 0-0.8-0.3-0.9-0.7-1.9-5.1-7-9-12.4-13-7.3-5.5-14.9-11.2-15.6-20.9-0.3-4.5 1.1-8.8 4.2-12 3-3.2 7.2-5.1 11.5-5.1 5.5 0 10.3 3.1 13.4 8.5-0.4 2.9 0.3 8.1 0.3 8.1l-1.7 4.6 5 4.5-6.2 5.8 6.4 2.4-4.2 3.8c0 7.4 0.4 7.4 0.3 13.7z" /> </g> </svg> 我们将心脏的两半连接到一个文件中,并开始为两半编写动画代码。 编写动画代码 动画非常简单 - 两半围绕不同方向的公共点旋转。 要顺时针旋转右半部分,请使用以下命令: <animateTransform id="break" attributeName="transform" type="rotate" begin="heart.click" dur="1s" repeatCount="1" values="0 50 75.7;7 50 75.7" fill="freeze" restart="whenNotActive"/> 动画开始 -begin="heart.click" 7 градусов绕坐标点旋转50 75.7-values="0 50 75.7;7 50 75.7" 对于左半部分,旋转将围绕同一点,但逆时针。因此,旋转角度会有一个负值: values="0 50 75.7;-7 50 75.7" 把它们放在一起: <svg id="heart" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="200" viewBox="0 0 100 100"> <style> #right-half, #left-half{ fill:#dc143c; } </style> <title>To break heart</title> <g> <path id="right-half" d="M63.9 24C58.5 24 53.5 27 50.2 32.5 49.8 35.3 50.5 40.6 50.5 40.6L48.8 45.2 53.8 49.7 47.6 55.5 54 57.8 49.8 61.6C49.7 69.1 50.2 69 50.1 75.4 50.1 75.4 50.2 75.7 50.2 75.7 50.6 75.7 51 75.5 51.1 75.1 53 70.1 58 66.3 63.4 62.2 70.9 56.5 78.6 50.7 79.2 41.1 79.4 36.4 77.9 32 74.8 28.8 73.5 27.4 72 26.3 70.4 25.5 68.4 24.5 66.1 24 63.9 24z"> <animateTransform id="break" attributeName="transform" type="rotate" begin="heart.click" dur="1s" repeatCount="1" values="0 50 75.7;7 50 75.7" fill="freeze" restart="whenNotActive"/> </path> </g> <g> <path id="left-half" d="m50.1 75.4c0 0 0.1 0.3 0.1 0.3-0.4 0-0.8-0.3-0.9-0.7-1.9-5.1-7-9-12.4-13-7.3-5.5-14.9-11.2-15.6-20.9-0.3-4.5 1.1-8.8 4.2-12 3-3.2 7.2-5.1 11.5-5.1 5.5 0 10.3 3.1 13.4 8.5-0.4 2.9 0.3 8.1 0.3 8.1l-1.7 4.6 5 4.5-6.2 5.8 6.4 2.4-4.2 3.8c0 7.4 0.4 7.4 0.3 13.7z" > <animateTransform attributeName="transform" type="rotate" begin="heart.click" dur="1s" repeatCount="1" values="0 50 75.7;-7 50 75.7" fill="freeze" restart="whenNotActive"/> </path> </g> </svg> 单击图标时动画开始 带有反向啄食的动画选项 <svg id="heart" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="200" viewBox="0 0 100 100"> <style> #right-half, left-half{ fill:#dc143c; } </style> <title>Icon to break and collect</title> <g> <path id="right-half" d="M63.9 24C58.5 24 53.5 27 50.2 32.5 49.8 35.3 50.5 40.6 50.5 40.6L48.8 45.2 53.8 49.7 47.6 55.5 54 57.8 49.8 61.6C49.7 69.1 50.2 69 50.1 75.4 50.1 75.4 50.2 75.7 50.2 75.7 50.6 75.7 51 75.5 51.1 75.1 53 70.1 58 66.3 63.4 62.2 70.9 56.5 78.6 50.7 79.2 41.1 79.4 36.4 77.9 32 74.8 28.8 73.5 27.4 72 26.3 70.4 25.5 68.4 24.5 66.1 24 63.9 24z"> <animateTransform id="break" attributeName="transform" type="rotate" begin="heart.click" dur="1s" repeatCount="1" values="0 50 75.7;7 50 75.7" fill="freeze" restart="whenNotActive"/> <animateTransform attributeName="transform" type="rotate" begin="break.end+1.5s" dur="1s" repeatCount="1" values="7 50 75.7;0 50 75.7" fill="freeze" restart="whenNotActive"/> </path> </g> <g> <path id="right-half" d="m50.1 75.4c0 0 0.1 0.3 0.1 0.3-0.4 0-0.8-0.3-0.9-0.7-1.9-5.1-7-9-12.4-13-7.3-5.5-14.9-11.2-15.6-20.9-0.3-4.5 1.1-8.8 4.2-12 3-3.2 7.2-5.1 11.5-5.1 5.5 0 10.3 3.1 13.4 8.5-0.4 2.9 0.3 8.1 0.3 8.1l-1.7 4.6 5 4.5-6.2 5.8 6.4 2.4-4.2 3.8c0 7.4 0.4 7.4 0.3 13.7z" > <animateTransform attributeName="transform" type="rotate" begin="heart.click" dur="1s" repeatCount="1" values="0 50 75.7;-7 50 75.7" fill="freeze" restart="whenNotActive"/> <animateTransform attributeName="transform" type="rotate" begin="break.end+1.5s" dur="1s" repeatCount="1" values="-7 50 75.7;0 50 75.7" fill="freeze" restart="whenNotActive"/> </path> </g> </svg> Best Answer Sevastopol' 2022-05-01T17:07:26Z2022-05-01T17:07:26Z css 实现如下: 使用属性绘制两颗心border-radius 将心放在彼此之上 使用属性clip-path: polygon(),指定断层线应该通过的必要坐标,我们将两半截断 当悬停在一个普通容器上时,使用属性rotate,我们应用旋转动画,属性translateX将元素水平移动到不同的方向 悬停动画: body {display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0;} .container {position: relative; width: 200px; height: 165px;} .heart__one, .heart__two { position: absolute; top: 0; left: 0; width: 200px; height: 165px; transition: all 2s 1s; } .heart__one { clip-path: polygon( 0 0, 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 0 100%); } .heart__two { clip-path: polygon( 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 100% 100%, 100% 0); } .heart__one::before, .heart__one::after, .heart__two::before, .heart__two::after { content: ""; position: absolute; top: 4px; left: 100px; width: 100px; height: 160px; background: #dc143c; border-radius: 100px 100px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; } .heart__one::after, .heart__two::after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; } .container:hover .heart__one { transform: rotate(-5deg) translateX(-7px); transition: all 1s; } .container:hover .heart__two { transform: rotate(5deg) translateX(7px); transition: all 1s; } <div class="container"> <div class="heart__one"></div> <div class="heart__two"></div> </div> 点击动画: let heart = document.querySelector('.container'); heart.onclick = function(){ document.querySelector('.heart__one').classList.add("heart__one__active"); document.querySelector('.heart__two').classList.add("heart__two__active"); setTimeout(function() { document.querySelector('.heart__one').classList.remove("heart__one__active"); document.querySelector('.heart__two').classList.remove("heart__two__active"); }, 1000); } body {display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0;} .container {position: relative; width: 200px; height: 165px;} .heart__one, .heart__two { position: absolute; top: 0; left: 0; width: 200px; height: 165px; transition: all 2s 1s; } .heart__one { clip-path: polygon( 0 0, 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 0 100%); } .heart__two { clip-path: polygon( 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 100% 100%, 100% 0); } .heart__one::before, .heart__one::after, .heart__two::before, .heart__two::after { content: ""; cursor: pointer; position: absolute; top: 4px; left: 100px; width: 100px; height: 160px; background: #dc143c; border-radius: 100px 100px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; } .heart__one::after, .heart__two::after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; } .heart__one__active { transform: rotate(-5deg) translateX(-7px); transition: all 1s; } .heart__two__active { transform: rotate(5deg) translateX(7px); transition: all 1s; } <div class="container"> <div class="heart__one"></div> <div class="heart__two"></div> </div> 让我们稍微复杂一点动画并添加灯光效果: let heart = document.querySelector('.container'); heart.onclick = function(){ document.querySelector('.heart__one').classList.add("heart__one__active"); document.querySelector('.heart__two').classList.add("heart__two__active"); document.querySelector('body').classList.add("body__black"); setTimeout(function() { document.querySelector('.heart__one').classList.remove("heart__one__active"); document.querySelector('.heart__two').classList.remove("heart__two__active"); document.querySelector('body').classList.remove("body__black"); }, 4600); } body {display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: pink;} .container {position: relative; width: 200px; height: 165px;} .heart__one, .heart__two { position: absolute; top: 0; left: 0; width: 200px; height: 165px; } .heart__one { clip-path: polygon( 0 0, 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 0 100%); } .heart__two { clip-path: polygon( 100px 0, 100px 40px, 90px 63px, 110px 80px, 90px 100px, 110px 120px, 100px 140px, 100px 100%, 100% 100%, 100% 0); } .heart__one::before, .heart__one::after, .heart__two::before, .heart__two::after { content: ""; cursor: pointer; position: absolute; top: 4px; left: 100px; width: 100px; height: 160px; background: #dc143c; border-radius: 100px 100px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; } .heart__one::after, .heart__two::after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; } .heart__one__active {animation: ani1 2s forwards 2.5s;} .heart__two__active {animation: ani2 2s forwards 2.5s;} @keyframes ani1 { 0% {transform: rotate(-8deg) translateX(-11px);} 2% {transform: rotate(-2deg) translateX(-3px);} 8% {transform: rotate(-7deg) translateX(-10px);} 13% {transform: rotate(-3deg) translateX(-4px);} 18% {transform: rotate(-6deg) translateX(-8px);} 22% {transform: rotate(-4deg) translateX(-5px);} 25% {transform: rotate(-5deg) translateX(-7px);} 60% {transform: rotate(-5deg) translateX(-7px);} 100% {transform: rotate(0deg) translateX(0);} } @keyframes ani2 { 0% {transform: rotate(8deg) translateX(11px);} 2% {transform: rotate(2deg) translateX(3px);} 8% {transform: rotate(7deg) translateX(10px);} 13% {transform: rotate(3deg) translateX(4px);} 18% {transform: rotate(6deg) translateX(8px);} 22% {transform: rotate(4deg) translateX(5px);} 25% {transform: rotate(5deg) translateX(7px);} 60% {transform: rotate(5deg) translateX(7px);} 100% {transform: rotate(0deg) translateX(0);} } .body__black {width: 100%; animation: ani 2s forwards 0.1s;} @keyframes ani { 0% {background: pink;} 100% {background: black;} } <div class="container"> <div class="heart__one"></div> <div class="heart__two"></div> </div> 结果很好。但一颗破碎的心并不总是好的,真的不可能把它粘在一起。因此,我希望大家永远只有这个: body {display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: pink;} .heart { position: relative; width: 200px; height: 165px; animation: ani1 1.5s infinite 0.5s; } .heart::before, .heart::after { content: ""; position: absolute; top: 4px; left: 100px; width: 100px; height: 160px; background: #dc143c; border-radius: 100px 100px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; animation: ani2 1.5s infinite 0.5s; } .heart::after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; } @keyframes ani1 { 10% {transform: scale(1.1);} 20% {transform: scale(1);} 30% {transform: scale(1.1);} 40% {transform: scale(1);} } @keyframes ani2 { 30% {background: red;} 50% {background: #dc143c;} } <div class="heart"></div>
要实现动画,您需要绘制一条断层线和两半图标。
我们获取第一个图标并将其加载到矢量编辑器中。
使用工具 - 绘制贝塞尔曲线和直线 -
画断线
Heart.svg在矢量编辑器中下面是右半部分的示例
图标的左半部分
编写动画代码
动画非常简单 - 两半围绕不同方向的公共点旋转。
要顺时针旋转右半部分,请使用以下命令:
动画开始 -
begin="heart.click"7 градусов绕坐标点旋转50 75.7-values="0 50 75.7;7 50 75.7"对于左半部分,旋转将围绕同一点,但逆时针。因此,旋转角度会有一个负值:
values="0 50 75.7;-7 50 75.7"把它们放在一起:
单击图标时动画开始
带有反向啄食的动画选项
css
实现如下:
border-radiusclip-path: polygon(),指定断层线应该通过的必要坐标,我们将两半截断rotate,我们应用旋转动画,属性translateX将元素水平移动到不同的方向悬停动画:
点击动画:
让我们稍微复杂一点动画并添加灯光效果:
结果很好。但一颗破碎的心并不总是好的,真的不可能把它粘在一起。因此,我希望大家永远只有这个: