You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

旋转矩形组成圆形时的SVG线性渐变填充问题

问题描述

我想给多个旋转后组成圆形的矩形添加渐变填充,最终效果要类似参考图(渐变圆形片段参考图),但每个矩形是独立不连接的片段。现在遇到的问题是所有矩形的填充效果完全一样。

尝试的最简示例

<svg width=300px height=300px viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient id="notchGradient" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
            <stop offset="0%" style="stop-color:blue;stop-opacity:1" />
            <stop offset="50%" style="stop-color:green;stop-opacity:1" />
            <stop offset="100%" style="stop-color:red;stop-opacity:1" />
        </linearGradient>
    </defs>
    <g transform="translate(50,50)" fill="url(#notchGradient)">
    <g>
        <g transform="rotate(0)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(90)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(180)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(270)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
    </g>
</svg>

我猜测是因为虽然矩形旋转后位置不同,但它们的原始坐标都是(0,-50)导致的。

另一种尝试:手动定位坐标

<svg width=300px height=300px overflow=visible viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient id="notchGradient" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
            <stop offset="0%" style="stop-color:blue;stop-opacity:1" />
            <stop offset="50%" style="stop-color:green;stop-opacity:1" />
            <stop offset="100%" style="stop-color:red;stop-opacity:1" />
        </linearGradient>
    </defs>
    <g fill="url(#notchGradient)">
        <g transform="rotate(0)" style="transform-box:fill-box;transform-origin:center;">
            <rect x="50" y="0" width="2" height="5"/>
        </g>
        <g transform="rotate(90)" style="transform-box:fill-box;transform-origin:center;">
            <rect x="100" y="50" width="2" height="5"/>
        </g>
        <g transform="rotate(180)" style="transform-box:fill-box;transform-origin:center;">
            <rect x="50" y="100" width="2" height="5"/>
        </g>
        <g transform="rotate(270)" style="transform-box:fill-box;transform-origin:center;">
            <rect x="0" y="50" width="2" height="5"/>
        </g>
    </g>
</svg>

这种方法能实现渐变,但需要手动计算每个矩形的坐标,如果要每隔几度放一个矩形,这种方式太麻烦,不合理。


解决方案

核心问题是你用了gradientUnits="userSpaceOnUse",这个属性会让渐变基于SVG的全局坐标系,而不是元素自身的局部坐标系。所以不管矩形怎么旋转,它们在全局坐标系里的对应区域渐变都是一样的。

有两种更高效的解决思路:

思路1:改用gradientUnits="objectBoundingBox"

把渐变的坐标系改成元素自身的边界框,这样每个矩形的渐变都会基于自己的局部方向,旋转后渐变也会跟着元素转。

修改后的代码:

<svg width=300px height=300px viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <!-- 改成objectBoundingBox,渐变基于元素自身的边界框 -->
        <linearGradient id="notchGradient" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
            <stop offset="0%" stop-color="blue" stop-opacity="1" />
            <stop offset="50%" stop-color="green" stop-opacity="1" />
            <stop offset="100%" stop-color="red" stop-opacity="1" />
        </linearGradient>
    </defs>
    <!-- 保持旋转+平移的简洁写法,不用手动算坐标 -->
    <g transform="translate(50,50)" fill="url(#notchGradient)">
        <g transform="rotate(0)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(90)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(180)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
        <g transform="rotate(270)">
            <rect x="0" y="-50" width="2" height="5"/>
        </g>
    </g>
</svg>

思路2:用JS批量生成矩形(适合大量元素)

如果需要生成很多间隔很小的矩形,手动写太麻烦,可以用JS循环生成,同时给每个矩形的渐变设置对应的旋转偏移,或者直接用objectBoundingBox配合旋转:

<svg width=300px height=300px viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient id="notchGradient" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
            <stop offset="0%" stop-color="blue" stop-opacity="1" />
            <stop offset="50%" stop-color="green" stop-opacity="1" />
            <stop offset="100%" stop-color="red" stop-opacity="1" />
        </linearGradient>
    </defs>
    <g id="notches" transform="translate(50,50)" fill="url(#notchGradient)"></g>
    <script>
        const notchGroup = document.getElementById('notches');
        const totalNotches = 20; // 要生成的矩形数量
        const angleStep = 360 / totalNotches; // 每个矩形的间隔角度

        for(let i=0; i<totalNotches; i++){
            const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
            rect.setAttribute('x', '0');
            rect.setAttribute('y', '-50');
            rect.setAttribute('width', '2');
            rect.setAttribute('height', '5');
            
            const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
            g.setAttribute('transform', `rotate(${i * angleStep})`);
            g.appendChild(rect);
            notchGroup.appendChild(g);
        }
    </script>
</svg>

这样不管你要生成多少个矩形,只需要修改totalNotches的值就行,不用手动计算每个坐标。

内容的提问来源于stack exchange,提问作者andy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:35:06