【问题标题】:CSS rotating smiling face loaderCSS 旋转笑脸加载器
【发布时间】:2018-06-22 07:22:32
【问题描述】:

我想用纯CSS复制下面的gif动画,有可能吗,怎么做?我也愿意接受其他合适的方法。

下面的 sn-p 是我目前所拥有的,它只是一张静态的脸。

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>

【问题讨论】:

    标签: css css-animations css-shapes


    【解决方案1】:

    2020 年更新

    一个新的优化版本,代码更少,我会让微笑的边缘更逼真:

    .smile {
      margin: 30px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background:
        radial-gradient(circle closest-side,#42bd56 99%,transparent) 
           -35px 42px/calc(100% - 15px) 15px repeat-x,
        linear-gradient(#fff,#fff) top/100% 50px no-repeat,
        radial-gradient(farthest-side,transparent calc(99% - 15px),#42bd56 calc(100% - 15px));
      position: relative;
    }
    
    .smile:before,
    .smile:after{
        content: "";
        position: absolute;
        width:100%;
        top: calc(50% - 7px);
        height: 15px;
        background:radial-gradient(circle closest-side,#42bd56 99%,transparent) -7.5px 0/200% 100%;
        transform:rotate(calc(var(--o,0deg) - 50deg));
        
    }
    .smile:after {
      --o:-80deg;
    }
    
    .smile:hover {
      animation: rotateS 1.2s linear;
    }
    .smile:hover:before,
    .smile:hover:after{
      animation: inherit;
      animation-name:rotateE;
    }
    
    @keyframes rotateS {
      50% {
        transform: rotate(360deg);
        background-size: calc(90% - 15px) 15px,100% 30px,auto;
        background-position:-25px 22px,top,0 0;
      }
      100% {
        transform: rotate(720deg);
      }
    }
    
    
    @keyframes rotateE {
      30%,70% {
        transform:rotate(calc(var(--o,0deg) - 180deg));
      }
    }
    Hover to animate
    <div class="smile">
    </div>

    Codepen 演示代码


    旧答案

    这里是解决方案,下面是一步一步的解释

    .smile {
      margin: 30px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background:
        radial-gradient(circle ,#42bd56 10%,transparent 11%)  43px 0px,
        radial-gradient(circle ,#42bd56 10%,transparent 11%) -43px 0px,
        radial-gradient(circle , #fff 35px, transparent 35px), 
        linear-gradient(to bottom, #fff 50%, transparent 50%), 
        #42bd56;
      background-repeat:no-repeat;
      position: relative;
    }
    
    .smile:before,.smile:after{
        content: "";
        position: absolute;
        width: 100%;
        top: 50%;
        margin-top: -7px;
        height: 15px;
        background: 
          radial-gradient(circle,#42bd56 15%,transparent 16%) 43px 0px;
        transform:rotate(-50deg);
        
    }
    .smile:after {
      background:
        radial-gradient(circle at center,#42bd56 15%,transparent 16%) -43px 0px;
      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);
      }
    }
    Hover to animate
    <div class="smile">
    </div>

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

    微笑

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

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

    现在要旋转微笑,我将使用旋转并更改线性渐变的大小。正如您在 GIF 中看到的,在旋转过程中曲线会增加,因此通过改变线性梯度的大小我会增加它。

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

    这是动画(悬停激活):

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

    眼睛

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

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

    .smile {
      margin: 50px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background:
       radial-gradient(circle at center,#42bd56 10%,transparent 11%)  43px 0px,
       radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px,
       radial-gradient(circle at center, #fff 35px, transparent 35px) , 
       linear-gradient(to bottom, #fff 50%, transparent 50%), 
       #42bd56;
      position: relative;
    }
    
    .smile:before,.smile:after{
        content: "";
        position: absolute;
        width: 100%;
        top: 50%;
        margin-top: -7px;
        height: 15px;
        background: radial-gradient(circle,#42bd56 15%,transparent 16%) 43px 0px;
        transform:rotate(-50deg);
        
    }
    .smile:after {
      background:radial-gradient(circle,#42bd56 15%,transparent 16%) -43px 0px;
      transform:rotate(50deg);
    }
    <div class="smile">
    </div>

    现在对于动画,我将保留第一次旋转,这也会旋转眼睛,但我会为眼睛添加一些动画,使它们朝相反的方向移动,并创造出微笑在它们上方的错觉。 所以我会简单地给眼睛添加一个负旋转,让它们看起来移动得更慢,从而超越微笑并创造所需的效果:

    这里是再次完整的动画:)

    .smile {
      margin: 50px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background:
       radial-gradient(circle at center,#42bd56 10%,transparent 11%)  43px 0px,
       radial-gradient(circle at center,#42bd56 10%,transparent 11%) -43px 0px,
       radial-gradient(circle at center, #fff 35px, transparent 35px) , 
       linear-gradient(to bottom, #fff 50%, transparent 50%), 
       #42bd56;
      background-repeat:no-repeat;
      position: relative;
    }
    
    .smile:before,.smile:after{
        content: "";
        position: absolute;
        width: 100%;
        top: 50%;
        margin-top: -7px;
        height: 15px;
        background: radial-gradient(circle,#42bd56 15%,transparent 16%) 43px 0px;
        transform:rotate(-50deg);
        
    }
    .smile:after {
      background:radial-gradient(circle,#42bd56 15%,transparent 16%)  -43px 0px;
      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);
      }
    }
    <div class="smile">
    </div>

    在这个解决方案中,为了简单起见,我使用了线性过渡,但可以将其更改为任何 ease function 以具有与 GIF 类似的过渡

    【讨论】:

      【解决方案2】:

      嗯,对于那种动画,从 CSS 调整 SVG 会更受欢迎。

      您用于绘制完整的 CSS 笑脸的技术依赖于衬里背景来调整线条的“长度”,如果在旋转时尝试动画​​(以增加长度),这将是可笑的资源密集型。

      最近我可以用纯 CSS 来调整你的代码,这不是 SVG,希望它有所帮助

      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);
        }
      }
      <div class="smiley ">
        <div class="loader">
        </div>
        <div class="dot-left"></div>
        <div class="dot-right"></div>
      </div>  

      【讨论】:

        【解决方案3】:

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

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

        这就是说,我做了一个你的smiley animation的例子。
        这就是它的样子:

        这里是代码(从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 制作平滑效果。动画时间也进行了调整,以更接近所需的笑脸动画。

        【讨论】:

        • 我提供了 CSS 解决方案,我完全同意您的观点,即 SVG 更适合此类事物,而 HTML/CSS 的目的不是绘制/动画此类事物,但这是一项更具挑战性的任务比别的 :) 通过只使用 CSS,我们必须考虑更多,我们可以找到一些技巧,让我们学习更多的 CSS,并且确信 OP 知道这一点,这就是他只在问题中标记 CSS 的原因。但是当涉及到生产和生活环境时,我们必须选择最好的替代方案,在这种情况下,首先是 GIF,然后是 SVG ;)
        • @TemaniAfif 我在挑战部分完全同意你的看法,我也喜欢这些,但这个问题需要一种 SVG 方法,因为它是“真实世界”的答案,可能对其他访问这里的人有用。在 svg 或 gif 问题上,两者都有优点和缺点,但现代标准,特别是如果需要交互,将使用 SVG。
        • 这是我认为真正正确的答案。 SVG 是一种方式
        • @FacundoCorradini 我是 OP,我最初问的是纯 css 解决方案的问题,虽然 svg 方法看起来更好,当然赞成,但我不会更改标记。跨度>
        • @Stickers 当然,我的评论更多是对 web-tiki 的祝贺,而不是请求切换接受的答案标记。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-11
        • 2021-05-03
        • 1970-01-01
        • 2014-10-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多