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

Canvas中能否结合clip为透明圆形添加shadowBlur阴影效果?

原因说明

shadowBlur 不生效是逻辑问题:Canvas的阴影只会渲染在实际执行填充/描边的图形上,你现在用的 clip() + clearRect() 是擦除像素的操作,不属于图形绘制,自然不会带出阴影效果。
你之前尝试的线性渐变方案方向不对,这种挖洞场景的边缘柔化,用径向渐变配合混合模式实现,效果和原生阴影完全一致。

正确实现代码

核心改动是去掉裁剪擦除的逻辑,改用 globalCompositeOperation = 'destination-out' 配合径向渐变绘制挖洞区域:中心区域完全不透明擦出全透的圆形,向外渐变到全透明,自然形成边缘模糊的阴影过渡。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .Preloader {
            background-color: #7bf;
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <div class="Preloader">
        <canvas id="myCanvas"></canvas>
    </div>
    <script>
        const c = document.getElementById("myCanvas");
        const ctx = c.getContext("2d");
        c.width = window.innerWidth;
        c.height = window.innerHeight;

        class Ball {
            constructor(x, y) {
                this.position = {x, y}
                this.r = 100
                // 阴影模糊范围,可自行调整
                this.shadowWidth = 20
            }
            draw() {
                // 先铺半透明黑色遮罩
                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                ctx.fillRect(0, 0, c.width, c.height);

                // 切换混合模式:绘制内容会擦除已有像素
                ctx.save()
                ctx.globalCompositeOperation = 'destination-out';
                // 创建径向渐变:中心全透擦除,向外渐变到0不擦,形成模糊边
                const gradient = ctx.createRadialGradient(
                    this.position.x, this.position.y, this.r - this.shadowWidth,
                    this.position.x, this.position.y, this.r + this.shadowWidth
                )
                gradient.addColorStop(0, '#000') // 完全不透明,100%擦除
                gradient.addColorStop(1, 'rgba(0,0,0,0)') // 完全透明,不擦除
                ctx.fillStyle = gradient
                ctx.beginPath()
                ctx.arc(this.position.x, this.position.y, this.r + this.shadowWidth, 0, Math.PI * 2)
                ctx.fill()
                ctx.restore()
            }
            update() {
                this.draw()
                this.position.x++
                this.position.y++
            }
        }

        const ball = new Ball(c.width / 2, c.height / 2)
        function animate() {
            requestAnimationFrame(animate);
            ctx.clearRect(0, 0, c.width, c.height);
            ball.update();
        };
        animate();

        window.addEventListener('resize', () => {
            c.width = window.innerWidth
            c.height = window.innerHeight
        })
    </script>
</body>
</html>
参数调整说明
  • 修改shadowWidth的值可以控制边缘模糊的范围,数值越大阴影越宽
  • 如果需要完全硬边的洞,把shadowWidth设为0即可
  • 渐变的中间色标可以自行调整,实现不同硬度的边缘过渡效果,比原生shadowBlur的可控性更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:57:26