如何用JS/Canvas实现平滑无硬边的同心径向渐变模糊甜甜圈效果
问题原因
渲染出现硬边由两个问题直接导致:
- 色标存在颜色跳变:三个色标的透明度虽然都是0.1,但颜色在0位置是黑色、0.5位置跳成灰色、1位置又跳回黑色,相邻色标之间的颜色值不连续,渲染时自然会出现清晰的分界
- 渐变创建逻辑不对:如果你的径向渐变是从圆心半径0的位置开始创建,中心区域会被直接填充,没法自然做出中间空心、内外边缘都柔化的环形效果。
实现方案
无硬边的模糊甜甜圈效果完全可以实现,核心逻辑是用同心双圆生成径向渐变,全程保持填充色一致,仅通过透明度的连续变化实现内外柔边,不要在色标位置做颜色或透明度的突变。
可直接运行的代码示例
const canvas = document.querySelector('canvas'); const ctx = canvas.getContext('2d'); // 甜甜圈参数,可按需调整 const cx = canvas.width / 2; const cy = canvas.height / 2; const innerRingRadius = 60; // 环形实体部分的内半径 const ringThickness = 30; // 环形实体部分的厚度 const edgeBlur = 20; // 边缘模糊的范围 const gradientInnerR = innerRingRadius - edgeBlur; const gradientOuterR = innerRingRadius + ringThickness + edgeBlur; // 创建同心径向渐变 const gradient = ctx.createRadialGradient( cx, cy, gradientInnerR, cx, cy, gradientOuterR ); // 配置色标:全程使用同一个灰色,仅调整透明度实现平滑过渡 const stopInnerSolid = edgeBlur / (gradientOuterR - gradientInnerR); const stopOuterSolid = (gradientOuterR - edgeBlur - gradientInnerR) / (gradientOuterR - gradientInnerR); gradient.addColorStop(0, "rgba(128, 128, 128, 0)"); gradient.addColorStop(stopInnerSolid, "rgba(128, 128, 128, 0.1)"); gradient.addColorStop(stopOuterSolid, "rgba(128, 128, 128, 0.1)"); gradient.addColorStop(1, "rgba(128, 128, 128, 0)"); // 填充圆形即可得到柔边甜甜圈 ctx.beginPath(); ctx.arc(cx, cy, gradientOuterR, 0, Math.PI * 2); ctx.fillStyle = gradient; ctx.fill(); // 想要更接近高斯模糊的柔化效果,可以额外加模糊滤镜,数值按需调整 // ctx.filter = 'blur(4px)';
关键注意点
- 不要在不同色标上切换颜色:之前代码里黑、灰、黑的跳变是硬边的直接来源,做柔边环形时全程使用同一个目标色,只改透明度就行
- 渐变内圆不要从半径0开始:把内圆半径设到内边缘模糊的起始位置,就能自然生成中心空心的效果,不需要额外擦除中心区域
- 透明度过渡不能有断点:从完全透明到目标透明度、再回到完全透明的过程要连续,不要在色标位置突然跳变透明度或颜色
- 如果需要更朦胧的效果,打开代码里注释的filter模糊属性即可,模糊半径越大边缘越柔和。
内容的提问来源于stack exchange,提问作者Atul Vinayak
相关产品推荐
相关产品推荐

