如何为圆形创建渐变边框动画?

huangapple go评论78阅读模式
英文:

How do I animate a gradient border of a circle?

问题

I have unsuccessfully been trying to animate a linear gradient border on a div. I took inspiration from this image. I want the border to be transparent between the two gradients, like in the picture. But I also want the gradient to look like it is moving in a circle around the circle div.

我一直在尝试对 div 上的线性渐变边框进行动画处理,但没有成功。我从 这个图片 中获取了灵感。我希望边框在两个渐变之间是透明的,就像图片中那样。但我还希望渐变看起来像是围绕 div 上的圆形移动。

I tried making the circle rotate in an animation, which works but I cannot add a gradient to a border-color property so instead I used an ::after property to add a circle behind the main div so that it looks like a circle. All of this works with a on the background but the main problem from here is that I cannot get the gaps between 2 different gradient borders on opposite sides of the circle.

我尝试通过动画使圆形旋转,这个方法有效,但我无法将渐变添加到 border-color 属性,所以我使用了 ::after 属性在主 div 后面添加了一个圆,以使它看起来像一个圆。这一切都在背景上运行,但从这里主要问题是我无法在圆的相对两侧获取两个不同渐变边框之间的间隙。

scss:

#home-page {
	i {
		position: absolute;
		color: $medium-red;
		top: 50%;
		left: 50%;
		font-size: 400px;
		animation: spin 4s linear infinite;
		border-radius: 50%;

		&::after {
			content: "";
			background: linear-gradient(60deg, $beige, $light-red);
			position: absolute;
			top: -3px;
			left: -3px;
			right: -3px;
			bottom: -3px;
			border-radius: 50%;
			z-index: -1;
		}
	}
}

@keyframes spin {
	0% {
		transform: translate(-50%, -50%);
	}

	100% {
		transform: translate(-50%, -50%) rotate(360deg);
	}
}

html:

<div id="homepage">
    <i>(font awesome icon of a circle)</i>
</div>
英文:

I have unsuccessfully been trying to animate a linear gradient border on a div. I took inspiration from
this image. I want the border to be transparent between the two gradients, like in the picture. But I also want the gradient to look like it is moving in a circle around the circle div.

I tried making the circle rotate in an animation, which works but I cannot add a gradient to a border-color property so instead I used an ::after property to add a circle behind the main div so that it looks like a circle. All of this works with a on the background but the main problem from here is that I cannot get the gaps between 2 different gradient borders on opposite sides of the circle.

scss:

#home-page {
	i {
		position: absolute;
		color: $medium-red;
		top: 50%;
		left: 50%;
		font-size: 400px;
		// border-width: 2px;
		// border-style: solid;
		animation: spin 4s linear infinite;
		// border-color: transparent $beige;
		border-radius: 50%;

		&amp;::after {
			content: &quot;&quot;;
			background: linear-gradient(60deg, $beige, $light-red);
			position: absolute;
			top: -3px;
			left: -3px;
			right: -3px;
			bottom: -3px;
			border-radius: 50%;
			z-index: -1;
		}
	}
}

@keyframes spin {
	0% {
		transform: translate(-50%, -50%);
	}

	100% {
		transform: translate(-50%, -50%) rotate(360deg);
	}
}

html:

&lt;div id=&quot;homepage&quot;&gt;
    &lt;i&gt;(font awesome icon of a circle)&lt;/i&gt;
&lt;/div&gt;

答案1

得分: 0

以下是您提供的HTML和CSS代码的翻译:

HTML

<div id="homepage">
    <div class="circle-gradient">
    </div>
</div>

CSS:

.circle-gradient {
    color: $medium-red;
    animation: spin 4s linear infinite;
    border-radius: 50%;
    position: relative;
    height: 300px;
    width: 300px;
    background: linear-gradient(60deg, $beige, $light-red);
    border-radius: 50%;
    z-index: -1;
    position: relative;
}

.circle-gradient::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: white;
    border-radius: 50%;
    z-index: 999;
    border-inline: 5px solid rgba(0, 0, 0, 0.02);
}

@keyframes spin {
    0% {
        transform: translate(1%, 1%);
    }

    100% {
        transform: translate(1%, 1%) rotate(360deg);
    }
}

在此链接上测试它的工作原理这里

英文:

HTML

&lt;div id=&quot;homepage&quot;&gt;
    &lt;div class=&quot;circle-gradient&quot;&gt;
    &lt;/div&gt;
&lt;/div&gt;

CSS:

.circle-gradient {
    color: $medium-red;
    animation: spin 4s linear infinite;
    border-radius: 50%;
    position: relative;
    height: 300px;
    width: 300px;
    background: linear-gradient(60deg, $beige, $light-red);
    border-radius: 50%;
    z-index: -1;
    position: relative;
    &amp;:after{
      content: &#39;&#39;;
      position: absolute;
      width: 100%;
      height: 100%;
      background-color: white;
      border-radius: 50%;
      z-index: 999;
      border-inline: 5px solid rgba(0,0,0,0.02);
    }
}

@keyframes spin {
  0% {
    transform: translate(1%, 1%);
  }

  100% {
    transform: translate(1%, 1%) rotate(360deg);
  }
}

test how it works HERE

答案2

得分: 0

以下是翻译好的部分:

* { margin: 0; }

body { background: #1a0a0a; }

.circle {
  position: relative;
  width: 10rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: url("https://i.stack.imgur.com/p2rd3.png") no-repeat center / 60%;
}

.circle svg {
  position: absolute;
  animation: arcRotation 2s linear infinite ;
}

@keyframes arcRotation {
  100% { rotate: 360deg; }
}
<div class="circle">
  <svg id="arc1" viewBox="0 0 1 1">
    <defs>
      <linearGradient id="gradient1" gradientUnits="userSpaceOnUse" x1="1" y1="1" x2="0" y2="1">
        <stop offset=".42" stop-color="#fff" />
        <stop offset=".58" stop-color="#f00" />
      </linearGradient>
    </defs>
    <path stroke="url(#gradient1)" stroke-width="0.01" fill="none" d="M 0.74 0.0843078061834695 A 0.48 0.48 0 0 0 0.2600000000000001 0.08430780618346945"></path>
  </svg>
  <svg id="arc2" viewBox="0 0 1 1">
    <defs>
      <linearGradient id="gradient2" gradientUnits="userSpaceOnUse" x1="1" y1="1" x2="0" y2="1">
        <stop offset=".42" stop-color="#f00" />
        <stop offset=".58" stop-color="#fff" />
      </linearGradient>
    </defs>
    <path stroke="url(#gradient2)" stroke-width="0.01" fill="none" d="M 0.37576685835079 0.9636443966187528 A 0.48 0.48 0 0 0 0.62423314164921 0.9636443966187528"></path>
  </svg>
</div>
// https://stackoverflow.com/a/18473154/383904
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
  const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
};

const describeArc = (x, y, radius, startAngle, endAngle) => {
  const start = polarToCartesian(x, y, radius, endAngle);
  const end = polarToCartesian(x, y, radius, startAngle);
  const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
  const d = [
    "M", start.x, start.y,
    "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(" ");
  return d;
};

document.querySelector("#arc1 path").setAttribute("d", describeArc(0.5, 0.5, 0.48, -30, 30));
document.querySelector("#arc2 path").setAttribute("d", describeArc(0.5, 0.5, 0.48, 180 - 15, 180 + 15));
英文:

You could use SVG for the gradient arcs like:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

* { margin: 0; }

body { background: #1a0a0a; }

.circle {
  position: relative;
  width: 10rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: url(&quot;https://i.stack.imgur.com/p2rd3.png&quot;) no-repeat center / 60%;
}

.circle svg {
  position: absolute;
  animation: arcRotation 2s linear infinite ;
}

@keyframes arcRotation {
  100% { rotate: 360deg; }
}

<!-- language: lang-html -->

&lt;div class=&quot;circle&quot;&gt;
  &lt;svg id=&quot;arc1&quot; viewBox=&quot;0 0 1 1&quot;&gt;
    &lt;defs&gt;
      &lt;linearGradient id=&quot;gradient1&quot; gradientUnits=&quot;userSpaceOnUse&quot; x1=&quot;1&quot; y1=&quot;1&quot; x2=&quot;0&quot; y2=&quot;1&quot;&gt;
        &lt;stop offset=&quot;.42&quot; stop-color=&quot;#fff&quot; /&gt;
        &lt;stop offset=&quot;.58&quot; stop-color=&quot;#f00&quot; /&gt;
      &lt;/linearGradient&gt;
    &lt;/defs&gt;
    &lt;path stroke=&quot;url(#gradient1)&quot; stroke-width=&quot;0.01&quot; fill=&quot;none&quot; d=&quot;M 0.74 0.0843078061834695 A 0.48 0.48 0 0 0 0.2600000000000001 0.08430780618346945&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;
  &lt;svg id=&quot;arc2&quot; viewBox=&quot;0 0 1 1&quot;&gt;
    &lt;defs&gt;
      &lt;linearGradient id=&quot;gradient2&quot; gradientUnits=&quot;userSpaceOnUse&quot; x1=&quot;1&quot; y1=&quot;1&quot; x2=&quot;0&quot; y2=&quot;1&quot;&gt;
        &lt;stop offset=&quot;.42&quot; stop-color=&quot;#f00&quot; /&gt;
        &lt;stop offset=&quot;.58&quot; stop-color=&quot;#fff&quot; /&gt;
      &lt;/linearGradient&gt;
    &lt;/defs&gt;
    &lt;path stroke=&quot;url(#gradient2)&quot; stroke-width=&quot;0.01&quot; fill=&quot;none&quot; d=&quot;M 0.37576685835079 0.9636443966187528 A 0.48 0.48 0 0 0 0.62423314164921 0.9636443966187528&quot;&gt;&lt;/path&gt;
  &lt;/svg&gt;
&lt;/div&gt;

<!-- end snippet -->

PS, the &lt;path&gt; elements d attribute was generated thanks to this snippet:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

// https://stackoverflow.com/a/18473154/383904
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) =&gt; {
  const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
};

const describeArc = (x, y, radius, startAngle, endAngle) =&gt; {
  const start = polarToCartesian(x, y, radius, endAngle);
  const end = polarToCartesian(x, y, radius, startAngle);
  const largeArcFlag = endAngle - startAngle &lt;= 180 ? &quot;0&quot; : &quot;1&quot;;
  const d = [
    &quot;M&quot;, start.x, start.y,
    &quot;A&quot;, radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(&quot; &quot;);
  return d;
};

document.querySelector(&quot;#arc1 path&quot;).setAttribute(&quot;d&quot;, describeArc(0.5, 0.5, 0.48, -30, 30));
document.querySelector(&quot;#arc2 path&quot;).setAttribute(&quot;d&quot;, describeArc(0.5, 0.5, 0.48, 180 - 15, 180 + 15));

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月3日 03:23:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76600466.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定