我能否在SVG路径上应用渐变?

91

我想在我的网站上放置一个简单的加载指示器,由脚本触发。它应该是一个简单的圆弧,具有渐变效果,当用户等待时旋转。我还没有尝试动画部分,但现在卡在了静态样式上。这是我到目前为止得到的:

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg"
        width="100" height="100">
        <defs>
            <linearGradient id="grad1">
                <stop offset="0%" stop-color="red"/>
                <stop offset="100%" stop-color="red" stop-opacity="0" />
            </linearGradient>
        </defs>
        <path d="M50 10  A40 40 0 1 0 90 50"
            stroke="url(#grad1)" stroke-width="10" fill="transparent"/>
    </svg>

它绘制了弧线,从顶部边缘逆时针到右侧边缘(270°),但是渐变是错误的。结果图像的弧形描边不是按照路径进行的,因此开始部分(顶部边缘,0°)不透明,结束部分(右侧边缘,270°)是透明的,相反,它在屏幕空间中从左到右着色。

如何让渐变沿着我的弧线路径进行?


相关链接:https://dev59.com/FGEh5IYBdhLWcg3wVCPK - TylerH
8个回答

32
Mike Bostock找到了一种方法,虽然不容易: https://bl.ocks.org/mbostock/4163057 基本上,这个技术使用getPointAtLength将描边切成许多短的线段,为每个线段指定插值的颜色停靠点,然后在这些停靠点之间的每个短线段上应用渐变效果。
祝你好运,如果你准备接受挑战的话;)
编辑(2019年7月3日): 现在有一个库可以帮助你做到你想要的。 不需要使用D3,但如果您愿意,也可以使用它。 这里是Medium上的教程

3
基本上这意味着“不”。Mike Bostock所做的是完全自己创建渐变。您可以复制他的代码并尝试修改以适应自己的需要,但像已经说过的那样,这并不简单... :) - gillyb
2
这些都是确切的例子,为什么我们现在迫切需要一个SVG标准更新!! - PrinceKickster

19

path{
 fill : url(#gradient)
}
<svg width="660" height="220">
  <defs>
    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%"   stop-color="#05a"/>
      <stop offset="100%" stop-color="#0a5"/>
    </linearGradient>
  </defs>
 <path d="M150 0 L75 200 L225 200 Z" />
</svg>


如果存在多个“路径”,则不会返回预期结果。 - Gonzalo Lorieto
4
这似乎与原始帖子中所遇到的从左到右而不是沿路径渐变的问题完全相同。 - theonlygusti

14

这种渐变在SVG中不易实现,详见SVG角度渐变

此外,在SVG中,transparent不是有效的颜色。您应该像这个例子一样声明stop-opacity: http://jsfiddle.net/WF2CS/

恐怕最简单的解决方案可能是使用透明度不同的小弧路径系列。


是的,我考虑过将许多小的弧段组合在一起,但不幸的是,你不能只指定一个边界框和起始和结束角度,而是需要告诉它停止的x和y坐标。这是一大堆十进制数和离线计算的混乱。 - ygoe

10
CSS图像模块4级引入了conic-gradient。根据MDN的说法,除IE外,所有主要浏览器都支持它(链接)
虽然从技术上讲,它不是沿着路径的渐变,因为你的路径是一个圆,但可以通过以下方式实现所需的效果:

.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; }
<div class="loader"></div>

相关的部分是

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

注意:如果不明显,CSS变量并非必需,我只是想找到一种在多个尺寸上测试而无需在多个位置修改值的方法。
注意:使用<svg />也可以实现对内部圆形的遮罩。我猜测它可能比mask有更好的浏览器支持。但这超出了本问题的范围。

发布时,我的示例在最新版的Chrome、Firefox和Edge中似乎按预期工作。没有测试Safari。不希望它能在任何版本的IE中工作。


到目前为止,这是最好的答案,而且纯CSS。谢谢! - JStanton

7

请使用@Dostonbek Oripjonov的方法,因为这种方法可以让浏览器的开发人员处理更新和修复。它还应该比JavaScript运行得更快。 - Jp Silver
做得好,@cereal。感谢你没有使用D3也让它可用。 - tao
@jpsilver:你似乎忽略了现代浏览器运行在 JavaScript 引擎上这一事实。你是说 JavaScript 比 JavaScript 好十倍吗?此外,你推荐的解决方案根本没有回答提出的问题。 - tao
@tao 不好意思,我表达得不够清楚,我的意思是优化后的JavaScript比普通JavaScript好10倍。浏览器的开发人员会编写最适合浏览器的代码,无论使用哪种编程语言,最好使用内置方法,因为它们更加优化。 - Jp Silver

1
另一种方法是制作两个半圆,并将相反的线性渐变应用于每个半圆的描边,并确保它们都包含在g元素中。(在我的示例中,组合渐变不是270度而是360度。两个半圆垂直堆叠。第一个渐变(应用于顶部半圆的描边)的不透明度为100-50%,然后下一个渐变为0%至50%。两个渐变都将单位向量设置为x1,y1,y2 = 0和x2 = 1,使它们从左到右运行。)然后将transform = rotate(deg,ctrX,ctrY)应用于g。

2
这听起来像是梯度分布不均匀。在每个半圆的中间速度更快,在它们连接的端点上则停滞不前。一个改进方法是使用4个四分之一圆,并且为了达到完美,你需要无限多的圆形线段...也就是渲染每个像素。 - ygoe

1

除了使用d3.js解决方案外,您可以使用GSAP和它们的MotionPathPlugin来解决问题。

这也涉及沿着路径放置彩色元素(圆形,矩形)。但对于GSAP用户来说,可能更容易。此外,如果需要,您还可以对其进行动画处理。

教程, codepen

const strokeWidth = 15;
const colors = ["#f7ff00", "#db36a4"];
const gradientPath = document.querySelector("#gradient-path");

const dotsDensity = .5 * strokeWidth;
const numberOfDots = Math.ceil(dotsDensity * gradientPath.getTotalLength() / strokeWidth);
const dotsGroup = document.querySelector(".dots");
createBasicGradient(dotsGroup);

function createBasicGradient(g) {
    for (let idx = 0; idx < numberOfDots; idx++) {
        const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        g.appendChild(circle);

        gsap.set(circle, {
            motionPath: {

                // the target path
                path: gradientPath,

                // the position on target path
                start: idx / numberOfDots,
                end: idx / numberOfDots,
            },
            attr: {

                // the position is defined by transform attribute, so we keep circle center on (0, 0) point
                cx: 0,
                cy: 0,

                // to compose strokeWidth
                r: .5 * strokeWidth,

                // linear interpolation between 2 (or more!) given colors
                fill: gsap.utils.interpolate(colors, (idx / numberOfDots))
            }
        });
    }
}
    html, body {
        margin: 0;
        padding: 0;
    }

    .container {
        width: 100%;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .container svg {
        height: 300px;
    }
    <svg width="0" height="0" viewBox="0 0 250 250">
        <defs>
            <path id="gradient-path" d="M36.5,91.2C-7.5,185.5,99.3,224.4,170,203.1c55-16.6,57.8-87.4,1.6-104C71,69.5,9.4,207.7,46,228.6c62.7,35.8,189.7-116,133-211"/>
            <mask id="gradient-path-clip">
                <use xlink:href="#gradient-path" stroke-width="15" fill="none" stroke="white"/>
            </mask>
        </defs>
    </svg>

    <div class="container">
        <svg viewBox="0 0 250 250">
            <g mask="url(#gradient-path-clip)" class="dots">
            </g>
        </svg>
    </div>

    <script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script>
    <script src="https://unpkg.com/gsap@3/dist/MotionPathPlugin.min.js"></script>


0

我成功地应用了一些渐变,参考了https://www.w3schools.com/graphics/svg_grad_radial.asp

例如: Codepen svg multiple path

<!DOCTYPE html>
<html>
<body>

<svg height="378" width="378" >
  <defs>
    <radialGradient id="grad1" cx="50%" cy="55%" r="50%">
    <stop offset="90%" style="stop-color:rgb(31, 175, 198); stop-opacity: .5" />
    <stop offset="100%" style="stop-color:rgb(161, 211, 60); stop-opacity: .5" />
    </radialGradient>
  </defs>
  <path d="M92.2871 10.1699C90.3999 25.8964 84.8432 45.0828 82.1173 45.0828C81.3834 45.0828 76.3509 42.986 71.0038 40.4697C62.4067 36.4856 49.3012 32.5016 44.4784 32.5016C43.2202 32.5016 43.8493 34.3888 46.8898 40.5746C51.5029 49.9057 55.6966 64.4789 55.1724 69.5114L54.8579 72.8664L45.422 73.6004C17.9529 75.6972 5.05709 76.9554 5.05709 77.4796C5.05709 77.899 9.67022 82.8266 15.3318 88.593C25.921 99.2871 33.6795 110.715 33.1552 114.699C32.9455 116.167 27.5985 120.57 16.5899 128.224C7.67819 134.41 0.234278 139.966 0.0245907 140.491C-0.185097 141.015 0.968185 141.749 2.64569 142.168C13.864 144.58 18.6868 146.152 22.6709 148.459C28.1227 151.709 33.7843 156.532 36.6151 160.516L38.712 163.451L26.9694 175.089C17.1141 184.944 15.4366 186.937 16.6948 188.09C17.5335 188.824 23.8241 191.235 30.7438 193.332C37.6635 195.429 43.7445 197.631 44.2687 198.155C44.7929 198.679 43.9541 204.026 41.9621 211.365C40.1798 218.18 39.0265 224.156 39.341 224.68C39.8652 225.624 57.1645 224.785 59.9952 223.737C62.6163 222.793 63.6648 225.309 64.3987 233.592C64.8181 238.415 65.4471 242.504 65.8665 242.713C66.7052 243.238 78.4478 238.205 78.4478 237.366C78.4478 237.052 77.0848 234.85 75.4073 232.439C70.5845 225.414 67.3343 218.18 64.2938 208.115C62.826 202.873 60.6243 195.848 59.5759 192.388C58.4226 188.929 57.2693 184.211 57.0596 181.904C55.5918 170.791 55.3821 166.702 56.4306 166.702C56.9548 166.702 57.479 168.484 57.479 170.581C57.5838 175.299 59.8904 187.88 61.4631 192.388C62.0921 194.066 64.0842 200.252 65.8665 206.018C70.1651 219.543 76.3509 231.705 81.6979 237.052C84.2142 239.568 89.666 243.133 94.9082 245.544L103.715 249.633L103.401 253.512L103.086 257.392L79.7059 265.15L56.3257 273.013L53.2852 282.973C51.6077 288.53 46.8898 304.991 42.696 319.669C38.5023 334.242 34.5182 346.823 33.8891 347.452C33.2601 348.081 31.3729 353.743 29.8002 360.138C28.2276 366.429 26.7598 372.51 26.4452 373.454C25.921 375.236 30.1148 375.341 104.554 375.341C179.098 375.341 183.292 375.236 183.292 373.454C183.292 372.51 178.364 367.058 172.283 361.397C166.202 355.735 161.274 350.493 161.274 349.654C161.274 348.92 165.049 345.041 169.557 341.057C181.09 331.202 181.195 330.573 176.477 318.515C168.509 298.281 151.419 267.037 145.128 261.166C143.136 259.279 142.402 257.496 142.402 254.666C142.402 250.367 143.346 249.319 148.693 247.536C154.145 245.754 159.492 241.665 163.162 236.528C166.097 232.439 167.355 231.705 175.428 229.189C180.356 227.616 184.34 225.938 184.34 225.519C184.34 224.995 182.453 222.269 180.146 219.543C175.638 214.091 174.799 210.212 177.84 209.268C178.783 208.954 182.453 208.429 185.913 208.01C189.372 207.696 192.518 207.171 192.937 206.857C193.881 206.437 188.534 191.55 187.276 191.025C186.856 190.816 186.437 189.872 186.437 188.824C186.437 187.566 187.905 186.622 191.679 185.678C198.179 184.001 213.696 176.557 213.696 175.194C213.696 174.565 211.704 173.097 209.293 171.839C195.873 165.024 184.969 157.161 187.171 155.903C187.59 155.693 191.469 154.435 195.663 153.177C199.857 151.919 206.672 149.298 210.865 147.41C218.1 144.16 232.988 135.353 232.358 134.724C231.939 134.41 203.526 122.248 200.8 121.304C199.542 120.78 199.228 120.151 199.752 119.207C200.171 118.369 207.091 111.659 215.059 104.32C222.923 96.8757 229.423 90.4802 229.423 90.0608C229.423 89.2221 222.922 88.0688 203.736 85.3429C196.816 84.2944 190.735 83.246 190.316 82.8266C189.792 82.4072 194.615 73.181 201.01 62.3821C211.39 44.6635 213.382 40.8891 212.333 40.8891C212.124 40.8891 203.526 43.9296 193.252 47.7039C178.259 53.1558 174.17 54.2043 173.122 53.1558C170.815 50.8493 168.613 33.55 168.613 18.0331V3.04048L160.121 7.54876C150.161 12.8958 136.846 23.2753 130.66 30.5096C128.353 33.3403 125.942 35.6469 125.523 35.6469C124.998 35.6469 121.014 30.8241 116.506 24.848C108.748 14.5733 95.6421 6.4671e-06 94.1743 6.4671e-06C93.7549 6.4671e-06 92.9162 4.61313 92.2871 10.1699ZM95.2228 272.908C91.3435 275.949 71.5281 328.266 73.1007 330.992C73.6249 331.935 78.1332 336.234 83.1657 340.638C88.3031 345.041 92.6017 349.13 92.8114 349.759C93.021 350.388 91.7629 352.695 89.9806 354.896C88.3031 357.098 86.8353 358.251 86.8353 357.517C86.8353 356.888 87.7788 355.001 89.037 353.533L91.2387 350.703L81.1737 341.267C74.1492 334.661 71.1087 331.097 71.1087 329.419C71.1087 326.064 83.0609 293.982 90.3999 277.522C92.1823 273.537 93.6501 271.545 94.9082 271.545C96.5857 271.65 96.5857 271.755 95.2228 272.908Z" fill="url(#grad1)"></path>
<path d="M270.733 147.306C241.272 152.653 225.021 164.29 203.948 195.429C199.335 202.139 199.02 202.978 199.02 209.478C199.02 214.51 197.972 219.438 195.246 227.93C190.633 242.294 190.842 245.649 197.447 256.867C200.068 261.271 202.165 265.465 202.165 265.989C202.165 266.618 200.802 268.61 199.02 270.497C193.463 276.473 193.568 285.699 199.335 291.885C202.69 295.345 210.553 298.595 212.65 297.232C213.174 296.918 212.44 294.506 211.077 291.78C209.609 289.159 208.456 286.224 208.561 285.28C208.561 284.232 209.085 284.546 209.714 286.224C211.496 290.103 219.779 302.894 223.868 307.926C231.941 317.991 249.345 328.161 265.596 332.46C270.524 333.718 279.226 334.871 286.565 335.186C293.484 335.5 298.202 336.129 297.049 336.549C290.758 338.75 261.821 334.661 248.506 329.629L241.587 327.008L239.804 329.419C233.199 338.121 225.65 357.937 223.763 371.357L223.239 375.341H288.242C349.681 375.341 353.245 375.236 352.721 373.454C352.407 372.51 350.729 366.219 349.052 359.509C345.382 345.041 342.446 337.807 337.728 331.621C335.841 329.105 334.269 326.484 334.269 325.75C334.373 325.121 336.994 322.604 340.245 320.298C346.116 316.104 354.189 307.612 358.592 300.902C360.06 298.7 362.367 296.918 364.464 296.289C366.246 295.764 369.601 293.563 371.907 291.466C379.142 284.546 379.876 275.11 373.48 269.553C371.278 267.666 370.964 266.723 371.593 263.368C372.012 261.271 372.641 259.279 373.061 258.964C373.48 258.65 374.424 255.609 375.158 252.149C376.206 247.117 376.206 243.238 375.158 232.439C374.424 225.1 373.375 219.124 372.851 219.124C372.327 219.124 372.012 216.188 372.117 212.518C372.327 206.752 371.803 204.97 368.028 197.631C362.996 187.67 355.552 176.767 348.003 168.589C343.39 163.556 340.349 161.564 328.502 155.693C320.115 151.604 311.517 148.144 307.324 147.306C298.622 145.418 280.798 145.418 270.733 147.306Z" fill="url(#grad1)"></path>
<path d="M147.646 261.69C147.646 262.005 149.638 264.94 152.154 268.19C154.67 271.441 158.13 276.578 160.017 279.409C164.945 287.272 176.373 311.805 179.728 321.556C183.397 331.935 183.083 332.669 172.074 342C167.88 345.565 164.421 349.34 164.421 350.178C164.421 351.122 169.138 356.154 174.905 361.606C181.196 367.373 185.389 372.091 185.389 373.349C185.389 375.236 186.228 375.341 200.067 375.341C211.076 375.341 214.746 375.026 214.746 373.978C214.746 369.574 189.059 277.207 186.647 272.804C186.228 271.965 179.518 269.763 171.76 267.771C164.001 265.884 155.928 263.577 153.726 262.634C149.428 260.956 147.646 260.642 147.646 261.69Z" fill="url(#grad1)"></path>
</svg>

</body>
</html>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接