ChatGPT解决这个技术问题 Extra ChatGPT

Can I apply a gradient along an SVG path?

I'd like to put a simple loading indicator on my website that's triggered by a script. It should be a simple circle arc that's got a gradient and is spinning while the user is waiting. I haven't tried the animation part, but got stuck on the static styling for now. Here's what I've got so far:

It draws the arc, from the top edge anti-clockwise to the right edge (270°), but the gradient is wrong. Instead of following the path so that the beginning (top edge, 0°) is opaque and the end (right edge, 270°) is transparent, the resulting image of the arc stroke is coloured from left to right in screen space.

How can I make the gradient follow my arc path?

May the downvoter please explain why they think this question is not worth asking?

c
cereallarceny

Mike Bostock figured out a way, though it's not easy: https://bl.ocks.org/mbostock/4163057

Basically, this technique uses getPointAtLength to slice the stroke into many short strokes, specify interpolated color stops for each, and then apply a gradient to each short stroke between those stops.

Good luck if you're up to the challenge ;)

Edit (July 3rd, 2019):

There is now a library that will help you do exactly what you're looking for. It's not required to use D3, but you're able to if you desire. Here's a tutorial on Medium.


Basically this means 'no'. What Mike Bostock did is create the gradient himself completely. You can copy his code, and try to modify it to suit your needs, but like said already, it won't be that simple... :)
These are the exact examples why we badly needed an SVG standard update now!!
C
Community

This type of gradient is not easy to achieve in SVG, see SVG angular gradient.

Also, transparent is not a valid color in SVG. You should state stop-opacity as in this example: http://jsfiddle.net/WF2CS/

I'm afraid the easiest solution might be a series of small arc paths with varying opacity.


Yes, I thought about combining many small arc segments, but unfortunately, you cannot just specify a bounding box and a start and stop angle, but you need to tell it the x and y coordinates where to stop. That's a big mess of decimal numbers and calculating them offline.
D
Dostonbek Oripjonov

path{ fill : url(#gradient) }


No the expected result if there is more than one path
t
tao

CSS Images Module - Level 4 has introduced conic-gradient. According to MDN, it's supported in all major browsers except IE.

Although it's not, technically, a gradient along a path, since your path is a circle, the desired outcome can be achieved with:

.loader { --size: 7.5rem; --stroke-size: .5rem; --diff: calc(calc(var(--size)/2) - var(--stroke-size)); background-image: conic-gradient(transparent 25%, red); width: var(--size); height: var(--size); border-radius: 50%; -webkit-mask:radial-gradient(circle var(--diff),transparent 98%,#fff 100%); mask:radial-gradient(circle var(--diff),transparent 98%,#fff 100%); animation: rotate 1.2s linear infinite; margin: 0 auto; } @keyframes rotate { from { transform: rotate(0); } to { transform: rotate(1turn); } } body { background: #f9fcfc url(https://picsum.photos/id/22/1323/880) 100% /cover; margin: 0; min-height: 100vh; padding-top: 2.5rem; } * { box-sizing: border-box; }

The relevant bit is

background-image: conic-gradient(transparent 25%, red);

Note: If not obvious, the CSS variables are not necessary, I just wanted a way to test it at multiple sizes without having to modify the values in more than one place.
Note: Masking the inner circle can also be achieved using an <svg />. I suspect it might have better browser support than mask. But that's outside of this question's scope.

At the time of posting, my example seems to work as expected in latest: Chrome, Firefox and Edge. Haven't tested Safari. Not expecting it to work in any version of IE.


Best answer on this yet, pure CSS too. Thank you!
c
cereallarceny

I had this problem as well, so I created a library to assist in the creation of gradients that follow along a path. You can use it standalone in Javascript or alongside D3.js if you prefer. The library is 100% based off of Mike Bostock's work referenced in the first answer, but I've removed D3 as a required dependency.

I've also written a brief tutorial on Medium describing the backstory and usage..


Please rather use @Dostonbek Oripjonov method because with this method the developers of the browsers will handle updates and fixes. it should also run x10 better than javascript.
Awesome work, @cereal. Props for making it available without D3.
@jpsilver: you seem to ignore the fact browsers these days run on JavaScript engines. Are you saying JavaScript is x10 better than JavaScript? Besides, the solution you recommend simply doesn't answer the question being asked.
@tao No sorry i was not very clear, i meant optimized javascript is 10x better than javascript, the developers of the browser wouldve written that best fits the browser, in any programming language its best to use the built in methods because they are more optimized.
A
Andrew Levino

Another way is to make two half circles and apply the opposite linear gradient to each's stroke, and make sure they are both contained in a g element. (In my example the combined gradient isn't 270 degrees but 360. Two half-circles are stacked vertically. The first gradient (applied to the top semi-circle's stroke) would be 100-50% opacity, then the next would have 0% to 50%. Both gradients have the unit vector set to x1,y1,y2=0 and x2=1, making them run from left to right.) Then apply transform=rotate(deg,ctrX,ctrY) to the g.


That sounds like the gradient is unevenly distributed. It goes faster in the middle of each half circle and stands still on their connecting ends. An improvement would be to use 4 quarter circles, and to get it perfect, you'd need infinitely many sircle segments... I. e. render every single pixel.
o
ouflak

I managed to apply some kind of gradient following https://www.w3schools.com/graphics/svg_grad_radial.asp.

e.g.: Codepen svg multiple path