CSS旋转微笑的脸装载机

时间:2018-01-12 19:30:25

标签: css css3 svg css-animations css-shapes

我想用纯CSS复制下面的gif动画,是否可能,以及如何?我也对其他适当的方法持开放态度。

下面的代码片段是我到目前为止它只是一个静态面孔。



body {
  background: #fff;
  margin: 50px;
}

.loader {
  position: relative;
  border-radius: 50%;
  box-sizing: border-box;
  width: 80px;
  height: 80px;
  background: linear-gradient(to bottom, #fff 50%, #51cf66 50%);
}

.loader:before {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  top: 10px;
  bottom: 10px;
  border-radius: 50%;
  background: #fff;
}

.dot {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #51cf66;
}

.dot:first-child {
  left: 10px;
  top: 10px;
}

.dot:last-child {
  right: 10px;
  top: 10px;
}

<div class="loader">
  <div class="dot"></div>
  <div class="dot"></div>
</div>
&#13;
&#13;
&#13;

Rotating smiley face animation

3 个答案:

答案 0 :(得分:7)

以下是解决方案,并在解释步骤之下:)

&#13;
&#13;
.smile {
  margin: 30px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background:radial-gradient(circle at center,#42bd56 10%,transparent 11%) 43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center, #fff 35px, transparent 35px) 0 0/100% 100% no-repeat, 
  linear-gradient(to bottom, #fff 50%, transparent 50%) 0 0/100% 100% no-repeat, #42bd56;
  position: relative;
}

.smile:before,.smile:after{
      content: "";
    position: absolute;
    width: 100%;
    top: 50%;
    margin-top: -7px;
    height: 15px;
    background: 
    radial-gradient(circle at center,#42bd56 15%,transparent 16%) 43px 0px/100% 100% no-repeat;
    transform:rotate(-50deg);
    
}
.smile:after {
  background:radial-gradient(circle at center,#42bd56 15%,transparent 16%) -43px 0px/100% 100% no-repeat;
  transform:rotate(50deg);
}


.smile:hover {
  animation: rotateS 1.5s linear;
}

.smile:hover::before {
  animation: rotateL 1.5s linear;
}
.smile:hover::after {
  animation: rotateR 1.5s linear;
}

@keyframes rotateS {
  0% {
    transform: rotate(0deg);
    background-size: auto,auto,auto ,100% 100%, auto;
  }
  50% {
    transform: rotate(360deg);
    background-size: auto,auto,auto, 100% 50%, auto;
  }
  100% {
    transform: rotate(720deg);
    background-size: auto,auto,auto, 100% 100%, auto;
  }
}

@keyframes rotateR {
  0% {
    transform:rotate(50deg);
  }
  30%,70% {
    transform:rotate(-40deg);
  }
  100% {
    transform:rotate(50deg);
  }
}

@keyframes rotateL {
  0% {
    transform:rotate(-50deg);
  }
  30%,70% {
    transform:rotate(-180deg);
  }

  100% {
    transform:rotate(-50deg);
  }
}
&#13;
Hover to animate
<div class="smile">
</div>
&#13;
&#13;
&#13;

在此解决方案中,我将仅使用一个元素。我将依赖于具有线性渐变和径向渐变的多个背景,并且还使用伪元素。

微笑

我将使用线性渐变和带背景颜色的径向渐变来创建主要形状,然后我将为圆角添加2个小径向渐变:

&#13;
&#13;
.smile {
  margin: 50px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background:radial-gradient(circle at center,#42bd56 10%,transparent 11%) 43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center, #fff 35px, transparent 35px) 0 0/100% 100% no-repeat, 
  linear-gradient(to bottom, #fff 50%, transparent 50%) 0 0/100% 100% no-repeat, #42bd56;
  position: relative;
}
&#13;
<div class="smile">
</div>
&#13;
&#13;
&#13;

现在要旋转笑脸,我将使用旋转,还可以更改线性渐变的大小。正如你在GIF中看到的那样,在旋转过程中曲线会增加,所以通过改变线性渐变的大小我会增加它。

enter image description here

你可以注意到用于圆角的小径向渐变在增加之后被隐藏,所以我们也可以考虑同时移动它们但是我不会这样做所以代码不要变得复杂

这是动画(悬停以激活):

&#13;
&#13;
.smile {
  margin: 50px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background:radial-gradient(circle at center,#42bd56 10%,transparent 11%) 43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center, #fff 35px, transparent 35px) 0 0/100% 100% no-repeat, 
  linear-gradient(to bottom, #fff 50%, transparent 50%) 0 0/100% 100% no-repeat, #42bd56;
  position: relative;
}

.smile:hover {
  animation: rotateS 1.5s linear;
}

@keyframes rotateS {
  0% {
    transform: rotate(0deg);
    background-size: auto,auto,auto ,100% 100%, auto;
  }
  50% {
    transform: rotate(360deg);
    background-size: auto,auto,auto, 100% 50%, auto;
  }
  100% {
    transform: rotate(720deg);
    background-size: auto,auto,auto, 100% 100%, auto;
  }
}
&#13;
<div class="smile">
</div>
&#13;
&#13;
&#13;

眼睛

对于眼睛,我将使用伪元素和径向渐变来创建圆。我不会简单地创建一个带有border-radius的圆圈,因为我还需要在与微笑相同的轴上旋转它们。

所以我们的想法是让它们全宽并使用径向渐变使圆圈最右边/左边。通过这样做,我可以通过旋转轻松控制它们的位置,并确保它们能够保持旋转度的需要。

enter image description here

&#13;
&#13;
.smile {
  margin: 50px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background:radial-gradient(circle at center,#42bd56 10%,transparent 11%) 43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center, #fff 35px, transparent 35px) 0 0/100% 100% no-repeat, 
  linear-gradient(to bottom, #fff 50%, transparent 50%) 0 0/100% 100% no-repeat, #42bd56;
  position: relative;
}

.smile:before,.smile:after{
      content: "";
    position: absolute;
    width: 100%;
    top: 50%;
    margin-top: -7px;
    height: 15px;
    background: 
    radial-gradient(circle at center,#42bd56 15%,transparent 16%) 43px 0px/100% 100% no-repeat;
    transform:rotate(-50deg);
    
}
.smile:after {
  background:radial-gradient(circle at center,#42bd56 15%,transparent 16%) -43px 0px/100% 100% no-repeat;
  transform:rotate(50deg);
}
&#13;
<div class="smile">
</div>
&#13;
&#13;
&#13;

现在对于动画,我将保持第一次旋转也会旋转眼睛,但我会在眼睛上添加一些动画,使它们向相反的方向移动,并创造出微笑的幻觉。 因此,我只需在眼睛上添加一个负旋转,这样它们就会移动得更慢,从而超越微笑并产生所需的效果:

这是再次完整的动画:)

&#13;
&#13;
.smile {
  margin: 50px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background:radial-gradient(circle at center,#42bd56 10%,transparent 11%) 43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px/100% 100% no-repeat,
  radial-gradient(circle at center, #fff 35px, transparent 35px) 0 0/100% 100% no-repeat, 
  linear-gradient(to bottom, #fff 50%, transparent 50%) 0 0/100% 100% no-repeat, #42bd56;
  position: relative;
}

.smile:before,.smile:after{
      content: "";
    position: absolute;
    width: 100%;
    top: 50%;
    margin-top: -7px;
    height: 15px;
    background: 
    radial-gradient(circle at center,#42bd56 15%,transparent 16%) 43px 0px/100% 100% no-repeat;
    transform:rotate(-50deg);
    
}
.smile:after {
  background:radial-gradient(circle at center,#42bd56 15%,transparent 16%) -43px 0px/100% 100% no-repeat;
  transform:rotate(50deg);
}


.smile:hover {
  animation: rotateS 1.5s linear;
}

.smile:hover::before {
  animation: rotateL 1.5s linear;
}
.smile:hover::after {
  animation: rotateR 1.5s linear;
}

@keyframes rotateS {
  0% {
    transform: rotate(0deg);
    background-size: auto,auto,auto ,100% 100%, auto;
  }
  50% {
    transform: rotate(360deg);
    background-size: auto,auto,auto, 100% 50%, auto;
  }
  100% {
    transform: rotate(720deg);
    background-size: auto,auto,auto, 100% 100%, auto;
  }
}

@keyframes rotateR {
  0% {
    transform:rotate(50deg);
  }
  30%,70% {
    transform:rotate(-40deg);
  }
  100% {
    transform:rotate(50deg);
  }
}

@keyframes rotateL {
  0% {
    transform:rotate(-50deg);
  }
  30%,70% {
    transform:rotate(-180deg);
  }

  100% {
    transform:rotate(-50deg);
  }
}
&#13;
<div class="smile">
</div>
&#13;
&#13;
&#13;

在此解决方案中,为简单起见,我使用了线性转换,但可以将其更改为任何ease function,以便与GIF进行类似的转换

答案 1 :(得分:5)

虽然这个笑脸动画只能使用CSS来实现,正如其他人所说,SVG显然是一个更好的选择,主要是出于以下原因:

  • 动画渐变不是最好的表现
  • 在没有添加非语义标记的情况下,在微笑的每一侧进行回合将非常难以实现
  • SVG是一种用于绘制这种形状并为其制作动画的工具。它使它们更易于维护,代码更易于阅读和理解

这就是说,我举了你smiley animation的例子 这是看起来像:

Smiley animation with CSS and SVG

以下是代码(简称codepen demo):

svg {
  width:100px;
  height:auto;
  display:block;
  transform:rotateZ(0deg);
  margin:0 auto;
}
.smile, .eyes {
  stroke:teal;
  stroke-width:1.3;
  stroke-linecap:round;
  fill:transparent;
}
svg:hover {animation:rotate 1.2s cubic-bezier(0.65, 0.000, 0.75, 1.000);}
svg:hover .smile{animation: smile 1s cubic-bezier(0.2, 0.000, 0.8, 1.000);}
svg:hover .eyes{animation: eyes 1s cubic-bezier(.7, 0.000, 0.4, 1.000);}

@keyframes rotate { to { transform:rotateZ(720deg); } }
@keyframes smile { 50% { stroke-dasharray:20,5.1327;} }
@keyframes eyes  { 70% { stroke-dasharray:1,0,.5,23.6327;} }
 
 h1 {text-align:center;color:teal;}
<svg viewbox="0 0 10 10">
  <circle class="smile" cx="5" cy="5" r="4" stroke-dashoffset="-.5" stroke-dasharray="11.5,13.6327" />
  <circle class="eyes" cx="5" cy="5" r="4" stroke-dashoffset="-15.5" stroke-dasharray="0,6.6327,0,17.5" />
</svg>
<h1>Hover me !</h1>

笑脸和动画是如何制作的?

这个笑脸是用两个SVG circle elements(一个用于眼睛,一个用于微笑)和stroke-dasharray属性来制作眼睛和微笑。

动画:
svg在悬停时使用CSS动画旋转,并且stroke-dasharray属性被动画化以使眼睛在微笑中“消失”。微笑的长度也变为大约3/4圈。

缓解功能:
使用bezier curve easing functions进行平滑效果。动画时间也会进行调整,以便更接近所需的笑脸动画。

答案 2 :(得分:4)

对于那种动画,从CSS调整SVG将是首选。

您用来绘制完整CSS笑脸的技术依赖于线性背景来调整&#34;长度&#34;该线路,在旋转时尝试动画​​(增加长度)会耗费大量资源。

最近我可以使用纯CSS调整你的代码而这个没有SVG,希望它有帮助

&#13;
&#13;
body {
  background: #fff;
  margin: 50px;
}

.smiley{
  position:relative;
  width: 70px;
  height: 70px;
}

.loader {
  position: relative;
  border-radius: 50%;
  box-sizing: border-box;
  width: 70px;
  height: 70px;
  background: linear-gradient(to bottom, #fff 50%, #51cf66 50%);
  animation: rotate 2s infinite;
}

.loader:before {
  content: "";
  position: absolute;
  left: 8px;
  right: 8px;
  top: 8px;
  bottom: 8px;
  border-radius: 50%;
  background: #fff;
}

.dot-left, .dot-right {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #51cf66;
}

.dot-left {
  left: 4px;
  top: 10px;
  animation: dissapearL 2s infinite;
}

.dot-right {
  right: 6px;
  top: 10px;
  animation: dissapearR 2s infinite;
}

@keyframes rotate{
  from{
    transform:rotate(0);
  }
  to{
    transform:rotate(720deg);
  }
}

@keyframes dissapearL{
  0%{
    transform:scale(1);
  }
  10%{
    transform:scale(1);
  }
  15%{
    transform:scale(0);
  }
  45%{
    transform:scale(0);
  }
  50%{
    transform:scale(1);
  }
}

@keyframes dissapearR{
  0%{
    transform:scale(1);
  }
  15%{
    transform:scale(1);
  }
  20%{
    transform:scale(0);
  }
  65%{
    transform:scale(0);
  }
  70%{
    transform:scale(1);
  }
}
&#13;
<div class="smiley ">
  <div class="loader">
  </div>
  <div class="dot-left"></div>
  <div class="dot-right"></div>
</div>  
&#13;
&#13;
&#13;