圆形加载动画

Circle loading animation

我正在尝试创建 Apple 的 OS X 圆圈加载动画。

到目前为止我尝试过的:

.animation-wrapper {
  width: 200px;
  height: 200px;
  border: 1px solid black;
  border-radius: 50%;
  position: relative;
  overflow: hidden;
  filter: brightness(0.8);
  -webkit-filter: brightness(0.8);
}
.pie-piece1 {
  position: absolute;
  width: 50%;
  height: 50%;
  bottom: 0;
  left: 0;
  background: linear-gradient(to right, rgba(255, 0, 0, 1) 0%, rgba(255, 255, 0, 1) 100%);
}
.pie-piece2 {
  position: absolute;
  width: 50%;
  height: 50%;
  bottom: 0;
  right: 0;
  background: linear-gradient(to right, rgba(255, 255, 0, 1) 0%, rgba(0, 255, 0, 1) 100%);
}
.pie-piece3 {
  position: absolute;
  width: 50%;
  height: 50%;
  top: 0;
  left: 0;
  background: linear-gradient(to right, rgba(255, 0, 0, 1) 0%, rgba(255, 0, 255, 1) 100%);
}
.pie-piece4 {
  position: absolute;
  width: 50%;
  height: 50%;
  top: 0;
  right: 0;
  background: linear-gradient(to right, rgba(255, 0, 255, 1) 0%, rgba(0, 0, 255, 1) 100%);
}
.rotating-spinners {
  position: absolute;
}
.spike {
  fill: rgba(22, 22, 22, 0.5);
}
<figure class="animation-wrapper">
  <div class="pie-piece1"></div>
  <div class="pie-piece2"></div>
  <div class="pie-piece3"></div>
  <div class="pie-piece4"></div>
  <svg class="rotating-spinners" width="100%" height="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="spin-part" class="spike" d="M 65,-40 C 65,-40 80,20 50,50 60,40 50,-40 50,-40Z" />
    </defs>
    <use x="0" y="0" xlink:href="#spin-part" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(60, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(120, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(180, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(240, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(300, 50, 50)" />
  </svg>
</figure>

线性渐变似乎没有正确对齐,因为我找不到使渐变朝两个方向移动的方法。

有没有一种方法可以只使用 CSS 或 SVG 来创建它,而不像我所做的那样混合它们?

或者我可以使用其他解决方案,例如 canvas 或某种图像魔术?

我不得不混合使用 SVG 和 CSS 渐变,我知道这是违反要求的,但我所知道的是。我使用了您的一些原始代码,主要是螺旋桨形状的 SVG 部分。

径向渐变使用 12 li 个元素制作。

.wheel,
.umbrella,
.color {
  content: "";
  position: absolute;
  border-radius: 50%;
  width: 15em;
  height: 15em;
  margin: 0;
  padding: 0;
}
.wheel {
  overflow: hidden;
  width: 15em;
  height: 15em;
  position: relative;
}
.umbrella {
  position: relative;
  -webkit-transform: scale(1.35);
}
.color,
.color:nth-child(n+7):after {
  clip: rect(0, 15em, 15em, 7.5em);
}
.color:after,
.color:nth-child(n+7) {
  content: "";
  position: absolute;
  border-radius: 50%;
  left: calc(50% - 7.5em);
  top: calc(50% - 7.5em);
  width: 15em;
  height: 15em;
  clip: rect(0, 7.5em, 15em, 0);
}
.color:nth-child(1):after {
  background-color: #9ED110;
  transform: rotate(30deg);
  z-index: 12;
}
.color:nth-child(2):after {
  background-color: #50B517;
  transform: rotate(60deg);
  z-index: 11;
}
.color:nth-child(3):after {
  background-color: #179067;
  transform: rotate(90deg);
  z-index: 10;
}
.color:nth-child(4):after {
  background-color: #476EAF;
  transform: rotate(120deg);
  z-index: 9;
}
.color:nth-child(5):after {
  background-color: #9f49ac;
  transform: rotate(150deg);
  z-index: 8;
}
.color:nth-child(6):after {
  background-color: #CC42A2;
  transform: rotate(180deg);
  z-index: 7;
}
.color:nth-child(7):after {
  background-color: #FF3BA7;
  transform: rotate(180deg);
}
.color:nth-child(8):after {
  background-color: #FF5800;
  transform: rotate(210deg);
}
.color:nth-child(9):after {
  background-color: #FF8100;
  transform: rotate(240deg);
}
.color:nth-child(10):after {
  background-color: #FEAC00;
  transform: rotate(270deg);
}
.color:nth-child(11):after {
  background-color: #FFCC00;
  transform: rotate(300deg);
}
.color:nth-child(12):after {
  background-color: #EDE604;
  transform: rotate(330deg);
}
<div class="wheel">
  <ul class="umbrella">
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
  </ul>
</div>


然后可以将这 12 个元素一起模糊以形成平滑的渐变。

然后我对旋转部分进行了动画处理以达到您需要的效果。

var rotation = 0;

$(document).ready(function() {
  setInterval(function() {
    rotation += 1;
    $('.wheel svg').css({
      'transform': 'rotate(' + rotation + 'deg)'
    });;
  }, 10);
});
.wheel,
.umbrella,
.color {
  content: "";
  position: absolute;
  border-radius: 50%;
  width: 15em;
  height: 15em;
  margin: 0;
  padding: 0;
}
.wheel {
  overflow: hidden;
  width: 15em;
  height: 15em;
  position: relative;
}
.umbrella {
  position: relative;
  filter: blur(.75em);
  -webkit-filter: blur(.75em);
  -moz-filter: blur(.75em);
  -o-filter: blur(.75em);
  -ms-filter: blur(.75em);
  filter: url(#blur);
  filter: progid: DXImageTransform.Microsoft.Blur(PixelRadius='.75');
  -webkit-transform: scale(1.35);
}
.color,
.color:nth-child(n+7):after {
  clip: rect(0, 15em, 15em, 7.5em);
}
.color:after,
.color:nth-child(n+7) {
  content: "";
  position: absolute;
  border-radius: 50%;
  left: calc(50% - 7.5em);
  top: calc(50% - 7.5em);
  width: 15em;
  height: 15em;
  clip: rect(0, 7.5em, 15em, 0);
}
.color:nth-child(1):after {
  background-color: #9ED110;
  transform: rotate(30deg);
  z-index: 12;
}
.color:nth-child(2):after {
  background-color: #50B517;
  transform: rotate(60deg);
  z-index: 11;
}
.color:nth-child(3):after {
  background-color: #179067;
  transform: rotate(90deg);
  z-index: 10;
}
.color:nth-child(4):after {
  background-color: #476EAF;
  transform: rotate(120deg);
  z-index: 9;
}
.color:nth-child(5):after {
  background-color: #9f49ac;
  transform: rotate(150deg);
  z-index: 8;
}
.color:nth-child(6):after {
  background-color: #CC42A2;
  transform: rotate(180deg);
  z-index: 7;
}
.color:nth-child(7):after {
  background-color: #FF3BA7;
  transform: rotate(180deg);
}
.color:nth-child(8):after {
  background-color: #FF5800;
  transform: rotate(210deg);
}
.color:nth-child(9):after {
  background-color: #FF8100;
  transform: rotate(240deg);
}
.color:nth-child(10):after {
  background-color: #FEAC00;
  transform: rotate(270deg);
}
.color:nth-child(11):after {
  background-color: #FFCC00;
  transform: rotate(300deg);
}
.color:nth-child(12):after {
  background-color: #EDE604;
  transform: rotate(330deg);
}
body {
  padding: 5px;
}
.wheel svg {
  position: absolute;
  top: 0;
  opacity: .5;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<figure class="animation-wrapper wheel">
  <ul class="umbrella">
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
  </ul>
  <svg class="rotating-spinners" width="100%" height="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="spin-part" class="spike" d="M 65,-40 C 65,-40 80,20 50,50 60,40 50,-40 50,-40Z" />
    </defs>
    <use x="0" y="0" xlink:href="#spin-part" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(60, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(120, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(180, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(240, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(300, 50, 50)" />
  </svg>
</figure>

Canvas进场

由于这是一个加载动画,其中的尺寸可能会在几乎没有用户交互的情况下固定,Canvas 也是一个不错的选择,因为它不会' 向 DOM 添加任何额外的元素。 Canvas 绘图命令与 SVG 非常相似,browser support 也不差。

一个缺点是 Canvas 没有自己的模糊滤镜(与 SVG 不同)。但这可以通过使用 CSS 模糊过滤器(具有非常低的浏览器支持)或 this Stack Overflow thread.

中提到的库来克服

背景渐变轮:

背景渐变轮是使用类似于 中详述的方法创建的。基本上我们在圆圈中找到多个点并绘制线条,每条线条都有不同颜色的笔划。通过修改每一行的 hue 值,我们可以绘制渐变轮。

在下面的截图中,第一张图片显示了如果我们只画了 24 条线(每条线之间 hue 变化 15)的背景效果,第二张是我们实际的渐变轮总共有 360 行,hue 每行递增 1。

范:

风扇是使用与您的 SVG 代码段中使用的相同方法创建的。路径命令用于绘制每个辐条。在 SVG 中使用 use 标签来重复形状,而在 Canvas 中可以使用循环。

SVG 和 Canvas 之间的主要区别在于 Canvas 不能将变换原点作为 rotate 函数的参数,因此必须将上下文转换为中心点在应用旋转之前。

最后 canvas 必须剪裁成圆形,因为默认形状是正方形(因为高度和宽度相同)。下面的屏幕截图显示了风扇的未剪裁和剪裁版本。

然后将这个扇子放在背景渐变轮的顶部。

立体效果:

顶部的 3D 效果是通过在背景和扇形上方添加透明度更高的小圆弧来提供的。

下面是没有任何动画的全图截图

动画:

动画是通过使用 window.requestAnimationFrame 方法添加的,该方法定期调用作为参数传递的函数。此方法通常每秒调用该函数约 60 次(根据 MDN)。通过在每次迭代期间增加 counter 变量的值并将其添加到风扇辐条的角度,可以实现动画效果。

window.onload = function() {
  var canvas = document.querySelector("#canvas"),
    ctx = canvas.getContext("2d"),
    counter = 360;

  function fan() {
    ctx.clearRect(0, 0, 100, 100);
    for (var i = 0; i < 360; i++) {
      ctx.strokeStyle = "hsl(" + (180 - i) + ", 60%, 50%)";
      ctx.beginPath();
      ctx.moveTo(50, 50);
      x = 50 + 50 * Math.cos((i / 360) * Math.PI * 2);
      y = 50 + 50 * Math.sin((i / 360) * Math.PI * 2)
      ctx.lineTo(x, y);
      ctx.lineWidth = 2;
      ctx.stroke();
    }
    counter++;
    for (var j = 0; j < 6; j++) {
      ctx.save();
      ctx.beginPath();
      ctx.arc(50, 50, 50, 0, Math.PI * 2, true);
      ctx.clip();
      ctx.translate(50, 50);
      ctx.rotate(((60 * j) + counter) * Math.PI / 180);
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.bezierCurveTo(0, 0, 30, 50, 100, 0);
      x = 75 * Math.cos((-20 / 360) * Math.PI * 2);
      y = 75 * Math.sin((-20 / 360) * Math.PI * 2)
      ctx.lineTo(x, y);
      ctx.bezierCurveTo(x, y, (x - 30), (y + 40), 0, 0);
      ctx.closePath();
      ctx.fillStyle = "rgba(0,0,0,0.5)";
      ctx.fill();
      ctx.restore();
    }
    ctx.save();
    ctx.beginPath();
    ctx.arc(50, 50, 50, 0, Math.PI, true);
    ctx.arc(50, 55, 50, Math.PI, 0, false);
    ctx.fillStyle = "rgba(0,0,0,0.15)";
    ctx.closePath();
    ctx.fill();
    ctx.restore();
    window.requestAnimationFrame(fan);
  }
  fan();
}
<canvas width='100px' height='100px' id='canvas'></canvas>


SVG 方法

与上述相同的方法也可以用于 SVG。唯一的缺点是没有。为背景和风扇添加到 DOM 的额外元素。

window.onload = function() {
  var colorWheel = document.querySelector("#color-wheel");
  for (var i = 0; i < 360; i++) {
    lineColor = "hsl(" + (180 - i) + ", 60%, 50%)";
    x = 50 + 50 * Math.cos((i / 360) * Math.PI * 2);
    y = 50 + 50 * Math.sin((i / 360) * Math.PI * 2);
    line = document.createElementNS("http://www.w3.org/2000/svg", "line");
    line.setAttribute('x1', 50);
    line.setAttribute('y1', 50);
    line.setAttribute('x2', x);
    line.setAttribute('y2', y);
    line.setAttribute('stroke', lineColor);
    line.setAttribute('stroke-width', 2);
    colorWheel.appendChild(line);
  }
}
<svg class="rotating-spinners" width="100px" height="100px" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <path id="spin-part" class="spike" d="M 50,50 c0,0 30,50 100,0 l-5,-35 c0,0 -30,50 -95,35Z" />
    <clipPath id="shape">
      <circle r="50" cx="50" cy="50" />
    </clipPath>
    <clipPath id="shade">
      <path d='M-5,55 a55,55 1 0,1 110,0 h-5 a50,50 1 0,0 -100,0' />
    </clipPath>
  </defs>
  <g id='color-wheel' clip-path='url(#shape)'>
  </g>
  <g id='fan' fill-opacity="0.5" clip-path='url(#shape)'>
    <use x="0" y="0" xlink:href="#spin-part" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(60, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(120, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(180, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(240, 50, 50)" />
    <use x="0" y="0" xlink:href="#spin-part" transform="rotate(300, 50, 50)" />
    <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0,50,50" to="360,50,50" dur="6s" repeatCount="indefinite" />
  </g>
  <circle r='50' cx='50' cy='50' fill-opacity='0.15' clip-path='url(#shade)' />
</svg>


混合方法

或者,如果您对风扇的额外元素没有问题,只是想避免添加 360 line 个元素,您可以混合使用 Canvas(对于背景)和 SVG,如下面的代码片段所示。

window.onload = function() {
  var canvas = document.querySelector("#canvas");
  var ctx = canvas.getContext("2d");

  for (var i = 0; i < 360; i++) {
    ctx.strokeStyle = "hsl(" + (180 - i) + ", 60%, 50%)";
    ctx.beginPath();
    ctx.moveTo(50, 50);
    x = 50 + 50 * Math.cos((i / 360) * Math.PI * 2);
    y = 50 + 50 * Math.sin((i / 360) * Math.PI * 2)
    ctx.lineTo(x, y);
    ctx.lineWidth = 2;
    ctx.stroke();
  }
  ctx.save();
  ctx.beginPath();
  ctx.arc(50, 50, 50, 0, Math.PI, true);
  ctx.arc(50, 55, 50, Math.PI, 0, false);
  ctx.fillStyle = "rgba(0,0,0,0.15)";
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}
div {
  position: relative;
  height: 100px;
  width: 100px;
}
canvas,
svg {
  position: absolute;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='container'>
  <canvas width='100px' height='100px' id='canvas'></canvas>
  <svg class="rotating-spinners" width="100%" height="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="spin-part" class="spike" d="M 50,50 c0,0 30,50 100,0 l-5,-35 c0,0 -30,50 -95,35Z" />
      <clipPath id="shape">
        <circle r="50" cx="50" cy="50" />
      </clipPath>
    </defs>
    <g id='fan' fill-opacity="0.5" clip-path="url(#shape)">
      <use x="0" y="0" xlink:href="#spin-part" />
      <use x="0" y="0" xlink:href="#spin-part" transform="rotate(60, 50, 50)" />
      <use x="0" y="0" xlink:href="#spin-part" transform="rotate(120, 50, 50)" />
      <use x="0" y="0" xlink:href="#spin-part" transform="rotate(180, 50, 50)" />
      <use x="0" y="0" xlink:href="#spin-part" transform="rotate(240, 50, 50)" />
      <use x="0" y="0" xlink:href="#spin-part" transform="rotate(300, 50, 50)" />
      <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0,50,50" to="360,50,50" dur="6s" repeatCount="indefinite" />
    </g>
  </svg>
</div>

这是我的纯 SVG 版本。背景色轮并不完美,但我觉得我已经很接近了。

<svg width="135" height="135" viewBox="0 0 200 200">
    <defs>
        <filter id="blur" color-interpolation-filters="linear">
            <feGaussianBlur in="SourceGraphic" stdDeviation="11"/>
        </filter>
        <mask id="mask">
            <circle cx="0" cy="0" r="90" fill="white"/>
        </mask>
        <linearGradient id="gloss" x2="0" y2="0.4">
            <stop offset="0" stop-color="white" stop-opacity="0.5"/>
            <stop offset="1" stop-color="white" stop-opacity="0"/>
        </linearGradient>
    </defs>

    <g transform="translate(100,100)" mask="url(#mask)">
        <g filter="url(#blur)">
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#c44"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#c09" transform="rotate(30)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#c0c" transform="rotate(60)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#90c" transform="rotate(90)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#44c" transform="rotate(120)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#09c" transform="rotate(150)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#0cc" transform="rotate(180)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#0c9" transform="rotate(210)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#4c4" transform="rotate(240)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#9c0" transform="rotate(270)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#cc0" transform="rotate(300)"/>
            <polygon points="0,0, -100,-26.8, -100,26.8" fill="#c90" transform="rotate(330)"/>
        </g>
        <g transform="scale(0.9,0.9)">
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4"/>
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4" transform="rotate(60)"/>
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4" transform="rotate(120)"/>
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4" transform="rotate(180)"/>
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4" transform="rotate(240)"/>
            <path d="M0,0C5,-61,-32,-86,-95,-90L-100,-46C-65,-53,-24,-35,0,0Z" fill="black" fill-opacity="0.4" transform="rotate(300)"/>
            <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="360" dur="4s" repeatCount="indefinite"/>

        </g>
        <circle r="83" fill="url(#gloss)"/>
        <circle r="90" fill="none" stroke="black" stroke-width="2"/>
    </g>
</svg>

这是我的努力。锥形渐变是通过计算OP发布的动画GIF中每个像素的最大值提取的嵌入式位图图像。一个半透明的黑色风车图案叠加在上面并进行动画处理,模糊滤镜去除了 JPEG 人工制品。

(编辑:添加了反光高光,使其看起来更立体)

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
  width="121" height="121" viewBox="0 0 121 121">
  <defs>
    <clipPath id="circ">
      <circle r="60" cx="60.5" cy="60.5"/>
    </clipPath>
    <linearGradient id="shine" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:#fff;stop-opacity:0.6" />
      <stop offset="10%" style="stop-color:#fff;stop-opacity:0.3" />
      <stop offset="20%" style="stop-color:#fff;stop-opacity:0.1" />
      <stop offset="40%" style="stop-color:#fff;stop-opacity:0" />
    </linearGradient>
    <filter id="blur">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2"/>
    </filter>
  </defs>
  <image width="121" height="121" filter="url(#blur)" xlink:href="data:image/jpeg;base64,
  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
  hIYYg5SFtM/cMbbeoFFHwc04MnGHKcXl/9k=" clip-path="url(#circ)" />
  <g transform="translate(60.5,60.5)">
    <path d="M0 0A56 56 0 0 0 0 56 56 56 0 0 0 32.916 45.305 56 56 0 0 1 0 0 56
        56 0 0 0 53.259 17.305 56 56 0 0 0 53.259-17.305 56 56 0 0 1 0 0 56 56
        0 0 0 32.916-45.305 56 56 0 0 0 0-56 56 56 0 0 1 0 0 56 56 0 0 0
        -32.916-45.305 56 56 0 0 0-53.259-17.305 56 56 0 0 1 0 0 56 56 0 0 0
        -53.259 17.305 56 56 0 0 0-32.916 45.305 56 56 0 0 1 0 0Z"
        stroke="none" fill="#000" opacity="0.25" transform="rotate(0)">
      <animateTransform attributeName="transform" type="rotate" from="0"
          to="72" begin="0s" dur="0.6s" repeatCount="indefinite" />
    </path>
    <circle r="59" stroke="#000" stroke-width="2" fill="none" opacity="0.25" />
    <circle r="55" fill="url(#shine)" stroke="none" />
  </g>
</svg>

这是一个纯粹的 CSS 解决方案,我将考虑仅使用 一个 元素。我将依赖于我创建的形状 and above I will consider a conic-gradient().

实际上 conic-gradient() 仅在 Chrome 和 Safari 中受支持,但我们很快就会提供更好的支持:

.box {
  --R:50px; /*Radius*/
  --c1:grey; /*first color*/
  --c2:#fff; /*second color*/
  
  --g1:var(--c1) 98%, transparent 100%;
  --g2:var(--c2) 98%, transparent 100%;
  width:calc(2*var(--R));
  height:calc(2*var(--R));
  border-radius:100%;
  border:1px solid;
  position:relative;
  overflow:hidden;
  display:inline-block;
  background:conic-gradient(rgba(128, 0, 128,0.7), rgba(0, 0, 255,0.7),rgba(0, 128, 0,0.7),rgba(255, 255, 0,0.7), rgba(255, 0, 0,0.7), rgba(128, 0, 128,0.7));
  box-shadow:0 3px 5px inset rgba(0,0,0,0.5);
}
.box::before,
.box::after{
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  bottom:0;
  left:0;
  width:50%;
  background:
     /*we rotate by 30deg so will use :
       sin(30deg)*R = 0.5xR   
       cos(30deg)*R = 0.866xR 
     */
    radial-gradient(circle var(--R) at calc(var(--R) + 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
    radial-gradient(circle var(--R) at calc(var(--R) + 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
    radial-gradient(circle var(--R) at var(--R)                        0                              ,var(--g1)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
    radial-gradient(circle var(--R) at 0                               var(--R)                        ,var(--g2)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) + 0.5*var(--R))  ,var(--g1));   
    transform-origin:right;
    animation:animate 3s linear infinite;
}

/*the same shape rotated*/
.box::after {
   animation-delay:-1.5s;
}

@keyframes animate {
  to {
    transform:rotate(-360deg);
  }
}
<div class="box"></div>

输出

这里是另一个方向(就像你的动画)

.box {
  --R:50px; /*Radius*/
  --c1:grey; /*first color*/
  --c2:#fff; /*second color*/
  
  --g1:var(--c1) 98%, transparent 100%;
  --g2:var(--c2) 98%, transparent 100%;
  width:calc(2*var(--R));
  height:calc(2*var(--R));
  border-radius:100%;
  border:1px solid;
  position:relative;
  overflow:hidden;
  display:inline-block;
  background:conic-gradient(rgba(128, 0, 128,0.7), rgba(0, 0, 255,0.7),rgba(0, 128, 0,0.7),rgba(255, 255, 0,0.7), rgba(255, 0, 0,0.7), rgba(128, 0, 128,0.7));
  box-shadow:0 3px 5px inset rgba(0,0,0,0.5);
}
.box::before,
.box::after{
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  bottom:0;
  left:0;
  width:50%;
  background:
     /*we rotate by 30deg so will use :
       sin(30deg)*R = 0.5xR   
       cos(30deg)*R = 0.866xR 
     */
    radial-gradient(circle var(--R) at calc(var(--R) + 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
    radial-gradient(circle var(--R) at calc(var(--R) + 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
    radial-gradient(circle var(--R) at var(--R)                        0                              ,var(--g1)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
    radial-gradient(circle var(--R) at 0                               var(--R)                        ,var(--g2)),
    radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) + 0.5*var(--R))  ,var(--g1));   
    transform-origin:right;
    animation:animate 3s linear infinite;
}

/*the same shape rotated*/
.box::after {
   animation-delay:-1.5s;
}

@keyframes animate {
  from {
    transform:scale(-1,1) rotate(0deg);
  }
  to {
    transform:scale(-1,1) rotate(-360deg);
  }
}
<div class="box"></div>

输出