本篇文章为Waxy主题设置中自定义CSS/JS的高级应用。

什么是Canvas?

Canvas 是 HTML5 中一个新特性,开发者绘制一系列图形。通过和JavaScript配合,可以使静态的图形动起来~

当然更加具体的内容,还请您自己学习,这里不做展开~

后面飞扬的花瓣就是基于Canvas技术实现的后面飞扬的花瓣就是基于Canvas技术实现的

如何自定义Canvas背景?

目前Waxy主题支持3种方式自定义Canvas背景,在文章后面,我提供了几个整理好的背景。

1.文件引入(推荐)

首先,您需要将要引入的背景文件,放入网站的目录下,并且保证可以读取。

这里我放在主题的js目录下这里我放在主题的js目录下

然后进入主题设置,自定义JS,中填入下面的代码:

<script type="text/javascript" src="【此处为该js文件相对与网站的路径地址】"></script>

注意替换src的路径注意替换src的路径

2.代码追加

打开主题下的/js/waxy-main.js文件。

在文件末尾换行一次或多次,将背景文件内所有内容复制进文件最后。

注意复制全了注意复制全了

3.全量设置

然后进入主题设置,自定义JS,中填入下面的代码:

<script type="text/javascript">此处为背景文件内所有的内容</script>

注意,一定不要丢 '&amp;lt;' 和 '&amp;gt;'注意,一定不要丢 '&amp;lt;' 和 '&amp;gt;'

附件

这些背景均搜集自网络,仅修改不兼容Waxy的部分,其他代码均未修改。保留原作者注释及声明
Canvas背景特效 浮动彩球
/* canvas背景特效 浮动彩球 */
(function () {
    // 1. 配置参数(多套配色,点击带 data-config-nr 属性的元素可切换)
    //    注:透明背景版已移除原来的渐变背景(colorStart/colorStop 保留但不再绘制),
    //    只保留彩球,便于叠加在任意主题之上。
    const configs = [
        {   // 0:暖白(默认)
            colorStart: "rgba(255,244,230,1)",
            colorStop: "rgba(255,233,228,1)",
            blur: 1,
            compose: "source-over",
            bubbleFunc: () => `hsla(${Math.random() * 50}, 100%, 50%, .3)`
        },
        {   // 1:暗红
            colorStart: "#111",
            colorStop: "#422",
            blur: 4,
            compose: "lighter",
            bubbleFunc: () => `hsla(0, 100%, 50%, ${Math.random() * 0.25})`
        },
        {   // 2:紫色霓虹
            colorStart: "#4c004c",
            colorStop: "#1a001a",
            blur: 4,
            compose: "lighter",
            bubbleFunc: () => `hsla(${Math.random() * 360}, 100%, 50%, ${Math.random() * 0.25})`
        },
        {   // 3:暖橙
            colorStart: "#fff4e6",
            colorStop: "#ffe9e4",
            blur: 1,
            compose: "source-over",
            bubbleFunc: () => `hsla(${Math.random() * 50}, 100%, 50%, .3)`
        }
    ];

    let canvas, ctx, width, height, balls, currentOpts;

    const random = () => Math.random();

    // 3. 生成小球数据
    function makeBalls(opts) {
        const count = Math.floor(0.02 * (width + height)); // 数量随屏幕尺寸自适应
        const list = [];
        for (let i = 0; i < count; i++) {
            list.push({
                color: opts.bubbleFunc(),          // 颜色
                x: random() * width,               // 初始 x
                y: random() * height,              // 初始 y
                r: 4 + random() * width / 25,      // 半径
                angle: random() * Math.PI * 2,     // 运动角度
                speed: 0.1 + 0.5 * random()        // 速度
            });
        }
        return list;
    }

    // 4. 初始化画布(透明沉底,直接挂 body,不拦截交互)
    function setupCanvas() {
        canvas = document.createElement('canvas');
        ctx = canvas.getContext('2d');
        canvas.style.cssText =
            'display:block;position:fixed;top:0;left:0;width:100%;height:100%;z-index:-1;background:transparent;pointer-events:none;';
        width = canvas.width = window.innerWidth;
        height = canvas.height = window.innerHeight;

        document.body.appendChild(canvas);
    }

    // 5. 应用一套配置(首次启动 & 点击切换共用)
    function applyConfig(opts) {
        currentOpts = opts;
        ctx.shadowColor = opts.shadowColor || "#fff";
        ctx.shadowBlur = opts.blur || 4;
        balls = makeBalls(opts);
    }

    // 6. 动画主循环
    function renderLoop() {
        // 透明清屏(不再铺渐变背景,让网站主题透出)
        ctx.clearRect(0, 0, width, height);

        // 普通叠加绘制小球(透明背景下 source-over 比 lighter 更自然)
        ctx.globalCompositeOperation = "source-over";
        balls.forEach(b => {
            ctx.beginPath();
            ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI);
            ctx.fillStyle = b.color;
            ctx.fill();

            // 移动
            b.x += Math.cos(b.angle) * b.speed;
            b.y += Math.sin(b.angle) * b.speed;

            // 边界环绕(飞出一侧从另一侧回来)
            if (b.x - b.r > width) b.x = -b.r;
            if (b.x + b.r < 0) b.x = width + b.r;
            if (b.y - b.r > height) b.y = -b.r;
            if (b.y + b.r < 0) b.y = height + b.r;
        });

        requestAnimationFrame(renderLoop);
    }

    // 7. 窗口尺寸变化(重设阴影,因为改 canvas 尺寸会重置上下文状态)
    window.addEventListener('resize', () => {
        width = canvas.width = window.innerWidth;
        height = canvas.height = window.innerHeight;
        ctx.shadowColor = currentOpts.shadowColor || "#fff";
        ctx.shadowBlur = currentOpts.blur || 4;
    });

    // 8. 点击切换配色(保留原功能)
    document.addEventListener('click', function (e) {
        if (e.target.hasAttribute('data-config-nr')) {
            const nr = parseInt(e.target.getAttribute('data-config-nr'), 10) || 0;
            applyConfig(configs[nr] || configs[0]);
        }
    });

    // 9. 自动启动
    setupCanvas();
    applyConfig(configs[0]);
    renderLoop();
})();
Canvas背景特效 彩色气泡
/* canvas背景特效 彩色气泡 */
(function () {
    // 1. 配置参数(完全私有,外部无法修改)
    const opts = {
        num: 100,               // 气泡最大数量
        start_probability: 0.1, // 每帧添加新气泡的概率
        radius_min: 1,          // 最小半径
        radius_max: 5,          // 最大半径
        radius_add_min: .1,     // 半径膨胀速度最小值
        radius_add_max: .3,     // 半径膨胀速度最大值
        opacity_min: 0.3,       // 初始透明度最小值
        opacity_max: 0.6,       // 初始透明度最大值
        opacity_prev_min: .003, // 透明度衰减速度最小值
        opacity_prev_max: .005, // 透明度衰减速度最大值
        light_min: 40,          // HSL亮度最小值
        light_max: 70,          // HSL亮度最大值
        is_same_color: false    // 是否所有气泡色调一致
    };

    let globalColor = Math.random() * 360;
    const bubbleList = []; // 存放气泡渲染闭包的数组
    let canvas, ctx;

    const random = (a, b) => Math.random() * (b - a) + a;

    // 3. 气泡工厂(核心闭包:为每个气泡锁定独立的状态变量)
    function makeBubble() {
        let x, y, radius, radiusChange, opacity, opacityChange, color;

        function init() {
            const light = random(opts.light_min, opts.light_max);
            x = random(0, canvas.width);
            y = random(0, canvas.height);
            radius = random(opts.radius_min, opts.radius_max);
            radiusChange = random(opts.radius_add_min, opts.radius_add_max);
            opacity = random(opts.opacity_min, opts.opacity_max);
            opacityChange = random(opts.opacity_prev_min, opts.opacity_prev_max);
            color = `hsl(${opts.is_same_color ? globalColor : random(0, 360)}, 100%, ${light}%)`;
        }

        init(); // 首次调用初始化

        // 返回的函数闭包了上方所有的局部变量
        return function updateAndDraw() {
            ctx.fillStyle = color;
            ctx.globalAlpha = opacity;
            ctx.beginPath();
            ctx.arc(x, y, radius, 0, 2 * Math.PI, true);
            ctx.closePath();
            ctx.fill();

            // 状态演变
            opacity -= opacityChange;
            radius += radiusChange;

            // 生命周期结束,原位重置(变量常驻内存,无需重新 new)
            if (opacity <= 0) {
                init();
            }
        };
    }

    // 4. 初始化画布(透明沉底,直接挂 body,不拦截交互)
    function setupCanvas() {
        canvas = document.createElement('canvas');
        ctx = canvas.getContext('2d');
        canvas.style.cssText =
            'position:fixed;top:0;left:0;width:100%;height:100%;z-index:-1;background:transparent;pointer-events:none;';
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        document.body.appendChild(canvas);

        window.onresize = () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        };
    }

    // 5. 动画主循环闭包
    function renderLoop() {
        globalColor += 0.1;

        // 擦除上一帧(透明清屏,不铺背景色)
        ctx.globalAlpha = 1;
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 渐进式生成新气泡闭包
        if (bubbleList.length < opts.num && Math.random() < opts.start_probability) {
            bubbleList.push(makeBubble());
        }

        // 执行每个气泡的闭包渲染逻辑
        bubbleList.forEach(drawBubble => drawBubble());

        window.requestAnimationFrame(renderLoop);
    }

    // 6. 自动启动
    setupCanvas();
    renderLoop();

})();
Canvas背景特效 动态彩带
/* canvas背景特效 动态彩带 */
(function () {
    // 1. 配置参数(完全私有,外部无法修改)
    const opts = {
        colorSaturation: "100%",    // 颜色饱和度
        colorBrightness: "60%",     // 颜色亮度
        colorAlpha: 0.80,           // 整体透明度
        colorCycleSpeed: 8,         // 色相循环速度
        verticalPosition: "center", // 起始垂直位置 top/center/bottom
        horizontalSpeed: 200,       // 水平展开速度
        ribbonCount: 5,             // 同屏彩带数量
        strokeSize: 0,              // 描边宽度(0 为不描边)
        parallaxAmount: -0.0,       // 滚动视差系数
        animateSections: true       // 是否让分段轻微浮动
    };

    // 3. 工具函数:random(max) / random(min,max) / random(array)
    const random = function () {
        if (arguments.length === 1) {
            if (Array.isArray(arguments[0])) {
                return arguments[0][Math.round(random(0, arguments[0].length - 1))];
            }
            return random(0, arguments[0]);
        } else if (arguments.length === 2) {
            return Math.random() * (arguments[1] - arguments[0]) + arguments[0];
        }
        return 0;
    };

    // 屏幕尺寸与滚动信息
    const screenInfo = function () {
        const w = window, d = document.documentElement, b = document.body;
        const width = Math.max(0, w.innerWidth || d.clientWidth || b.clientWidth || 0);
        const height = Math.max(0, w.innerHeight || d.clientHeight || b.clientHeight || 0);
        const scrolly = Math.max(0, w.pageYOffset || d.scrollTop || b.scrollTop || 0) - (d.clientTop || 0);
        return { width, height, scrolly };
    };

    // 4. 二维点(仅保留彩带用得到的方法)
    function Point(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    }
    Point.prototype.copy = function (p) { this.x = p.x || 0; this.y = p.y || 0; return this; };
    Point.prototype.add = function (x, y) { this.x += x || 0; this.y += y || 0; return this; };
    Point.prototype.subtract = function (x, y) { this.x -= x || 0; this.y -= y || 0; return this; };

    let canvas, ctx, width = 0, height = 0, scroll = 0;
    const ribbons = []; // 每条彩带 = 若干三角形分段组成的数组

    // 5. 初始化画布
    function setupCanvas() {
        canvas = document.createElement('canvas');
        canvas.id = 'bg_canvas';
        canvas.style.cssText = 'display:block;position:fixed;margin:0;padding:0;border:0;left:0;top:0;width:100%;height:100%;z-index:-1;background:transparent;pointer-events:none;';
        onResize();
        ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, width, height);
        ctx.globalAlpha = opts.colorAlpha;

        window.addEventListener('resize', onResize);
        window.addEventListener('scroll', onScroll);

        document.body.appendChild(canvas);
    }

    function onResize() {
        const s = screenInfo();
        width = s.width;
        height = s.height;
        if (canvas) {
            canvas.width = width;
            canvas.height = height;
            if (ctx) ctx.globalAlpha = opts.colorAlpha;
        }
    }

    function onScroll() {
        scroll = screenInfo().scrolly;
    }

    // 6. 新增一条彩带
    function addRibbon() {
        const dir = Math.round(random(1, 9)) > 5 ? "right" : "left"; // 展开方向
        const hide = 200;                                            // 屏幕外预留
        const min = 0 - hide, max = width + hide;
        let stop = 1000, movex = 0, movey = 0, delay = 0;
        const startx = dir === "right" ? min : max;
        let starty = Math.round(random(0, height));

        // 起始垂直位置
        if (/^(top|min)$/i.test(opts.verticalPosition)) starty = 0 + hide;
        else if (/^(middle|center)$/i.test(opts.verticalPosition)) starty = height / 2;
        else if (/^(bottom|max)$/i.test(opts.verticalPosition)) starty = height - hide;

        const ribbon = [];
        const point1 = new Point(startx, starty);
        const point2 = new Point(startx, starty);
        let point3 = null;
        let color = Math.round(random(0, 360));

        // 逐段生成,直到走出屏幕或达到上限
        while (true) {
            if (stop <= 0) break;
            stop--;
            movex = Math.round((Math.random() * 1 - 0.2) * opts.horizontalSpeed);
            movey = Math.round((Math.random() * 1 - 0.5) * (height * 0.25));
            point3 = new Point().copy(point2);
            if (dir === "right") {
                point3.add(movex, movey);
                if (point2.x >= max) break;
            } else {
                point3.subtract(movex, movey);
                if (point2.x <= min) break;
            }
            ribbon.push({
                point1: new Point(point1.x, point1.y),
                point2: new Point(point2.x, point2.y),
                point3: point3,
                color: color, delay: delay, dir: dir, alpha: 0, phase: 0
            });
            point1.copy(point2);
            point2.copy(point3);
            delay += 4;
            color += opts.colorCycleSpeed;
        }
        ribbons.push(ribbon);
    }

    // 7. 绘制单个分段,返回 true 表示该分段生命周期结束
    function drawSection(section) {
        if (!section) return false;
        if (section.phase >= 1 && section.alpha <= 0) return true;

        if (section.delay <= 0) {
            // 用 sin 曲线做淡入淡出
            section.phase += 0.02;
            section.alpha = Math.sin(section.phase);
            section.alpha = section.alpha <= 0 ? 0 : (section.alpha >= 1 ? 1 : section.alpha);

            // 分段轻微浮动
            if (opts.animateSections) {
                const mod = Math.sin(1 + section.phase * Math.PI / 2) * 0.1;
                if (section.dir === "right") {
                    section.point1.add(mod, 0); section.point2.add(mod, 0); section.point3.add(mod, 0);
                } else {
                    section.point1.subtract(mod, 0); section.point2.subtract(mod, 0); section.point3.subtract(mod, 0);
                }
                section.point1.add(0, mod); section.point2.add(0, mod); section.point3.add(0, mod);
            }
        } else {
            section.delay -= 0.5; // 延迟出现
        }

        const c = `hsla(${section.color}, ${opts.colorSaturation}, ${opts.colorBrightness}, ${section.alpha})`;
        ctx.save();
        if (opts.parallaxAmount !== 0) ctx.translate(0, scroll * opts.parallaxAmount);
        ctx.beginPath();
        ctx.moveTo(section.point1.x, section.point1.y);
        ctx.lineTo(section.point2.x, section.point2.y);
        ctx.lineTo(section.point3.x, section.point3.y);
        ctx.fillStyle = c;
        ctx.fill();
        if (opts.strokeSize > 0) {
            ctx.lineWidth = opts.strokeSize;
            ctx.strokeStyle = c;
            ctx.lineCap = "round";
            ctx.stroke();
        }
        ctx.restore();
        return false;
    }

    // 8. 动画主循环
    function renderLoop() {
        ctx.clearRect(0, 0, width, height);

        // 绘制所有彩带,全部分段结束的整条置空
        for (let a = 0; a < ribbons.length; a++) {
            const ribbon = ribbons[a];
            if (!ribbon) continue;
            let done = 0;
            for (let b = 0; b < ribbon.length; b++) {
                if (drawSection(ribbon[b])) done++;
            }
            if (done >= ribbon.length) ribbons[a] = null;
        }

        // 清理已结束的彩带
        for (let i = ribbons.length - 1; i >= 0; i--) {
            if (!ribbons[i]) ribbons.splice(i, 1);
        }

        // 数量不足则补充
        if (ribbons.length < opts.ribbonCount) addRibbon();

        requestAnimationFrame(renderLoop);
    }

    // 9. 自动启动
    setupCanvas();
    renderLoop();
})();
Canvas背景特效 粒子网络
/* canvas背景特效 粒子网络 */
(function () {
    // 1. 配置参数(原版从 script 标签属性读取,这里改为内联,完全私有)
    const opts = {
        zIndex: -1,             // canvas 层级
        opacity: 1,             // 整体透明度
        color: "190,189,188",   // 点/连线颜色 RGB
        count: 150,             // 粒子数量
        dist: 6000,             // 粒子间连线的距离阈值(距离平方)
        mouseDist: 20000        // 鼠标吸附/连线的距离阈值(距离平方)
    };

    let canvas, ctx, width, height;
    let particles = [];
    const mouse = { x: null, y: null, max: opts.mouseDist }; // 鼠标作为一个特殊点
    let allPoints;

    const random = Math.random;

    // 3. 初始化画布(透明沉底,直接挂 body,不拦截交互)
    function setupCanvas() {
        canvas = document.createElement('canvas');
        ctx = canvas.getContext('2d');
        canvas.style.cssText =
            `position:fixed;top:0;left:0;width:100%;height:100%;z-index:${opts.zIndex};opacity:${opts.opacity};background:transparent;pointer-events:none;`;
        setSize();

        document.body.appendChild(canvas);

        window.addEventListener('resize', setSize);
    }

    function setSize() {
        width = canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
        height = canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    }

    // 4. 生成粒子
    function makeParticles() {
        particles = [];
        for (let i = 0; i < opts.count; i++) {
            particles.push({
                x: random() * width,
                y: random() * height,
                xa: 2 * random() - 1,   // x 方向速度
                ya: 2 * random() - 1,   // y 方向速度
                max: opts.dist
            });
        }
        // 把鼠标点拼到末尾,参与连线计算
        allPoints = particles.concat([mouse]);
    }

    // 5. 鼠标交互
    function bindMouse() {
        window.onmousemove = e => {
            e = e || window.event;
            mouse.x = e.clientX;
            mouse.y = e.clientY;
        };
        window.onmouseout = () => {
            mouse.x = null;
            mouse.y = null;
        };
    }

    // 6. 动画主循环
    function renderLoop() {
        ctx.clearRect(0, 0, width, height);
        let target, dx, dy, dist, d;

        particles.forEach((p, idx) => {
            // 移动
            p.x += p.xa;
            p.y += p.ya;
            // 碰到边界反向反弹
            p.xa *= (p.x > width || p.x < 0) ? -1 : 1;
            p.ya *= (p.y > height || p.y < 0) ? -1 : 1;
            // 绘制一个 1px 的点
            ctx.fillRect(p.x - 0.5, p.y - 0.5, 1, 1);

            // 与后续点(含鼠标)连线
            for (let i = idx + 1; i < allPoints.length; i++) {
                target = allPoints[i];
                if (target.x === null || target.y === null) continue;
                dx = p.x - target.x;
                dy = p.y - target.y;
                dist = dx * dx + dy * dy;
                if (dist < target.max) {
                    // 靠近鼠标时被轻微吸引
                    if (target === mouse && dist >= target.max / 2) {
                        p.x -= 0.03 * dx;
                        p.y -= 0.03 * dy;
                    }
                    d = (target.max - dist) / target.max; // 越近越不透明
                    ctx.beginPath();
                    ctx.lineWidth = d / 2;
                    ctx.strokeStyle = `rgba(${opts.color},${d + 0.2})`;
                    ctx.moveTo(p.x, p.y);
                    ctx.lineTo(target.x, target.y);
                    ctx.stroke();
                }
            }
        });

        requestAnimationFrame(renderLoop);
    }

    // 7. 自动启动
    setupCanvas();
    makeParticles();
    bindMouse();
    setTimeout(renderLoop, 100);
})();
Canvas动画背景 漂浮气泡
// Canvas 动画背景 漂浮气泡
(function () {
  // 创建背景专用 Canvas
  const bgCanvas = document.createElement('canvas');
  const ctx = bgCanvas.getContext('2d');
  document.body.appendChild(bgCanvas);

  // background: transparent 确保完全透明,完美适应任何网页主题
  bgCanvas.style.cssText = 'position:fixed;top:0;left:0;z-index:-1;width:100%;height:100%;background:transparent;pointer-events:none;';

  function resize() {
    bgCanvas.width = window.innerWidth;
    bgCanvas.height = window.innerHeight;
  }
  window.addEventListener('resize', resize);
  resize();

  let bubbles = [];
  const BUBBLE_COUNT = 45; // 气泡数量,可根据需要增减

  class Bubble {
    constructor() {
      this.init(true); // 首次初始化,随机散落在屏幕各处
    }

    init(isFirstTime = false) {
      this.radius = Math.random() * 35 + 15; // 气泡半径(15px 到 50px)
      this.x = Math.random() * bgCanvas.width;

      // 首次随机分布全屏,后续则严格从底部(屏幕高度 + 半径)升起
      this.y = isFirstTime ? Math.random() * bgCanvas.height : bgCanvas.height + this.radius;

      this.vy = -(Math.random() * 0.7 + 0.3); // 上升速度
      this.wobbleSpeed = Math.random() * 0.02; // 左右摇摆频率
      this.wobble = Math.random() * Math.PI; // 初始摇摆弧度

      // 七彩随机色:HSL 色相(0~360) 完美覆盖彩虹色系
      // 饱和度 85%(色彩鲜艳)、亮度 65%(柔和不刺眼)、透明度 0.25(半透明,可完美叠在任何主题上)
      this.color = `hsla(${Math.floor(Math.random() * 360)}, 85%, 65%, 0.25)`;
    }

    update() {
      this.y += this.vy;
      this.wobble += this.wobbleSpeed;
      this.x += Math.sin(this.wobble) * 0.4; // 模拟水流左右晃动

      // 飘出顶部后,重置回底部重新生成新气泡
      if (this.y < -this.radius) {
        this.init(false);
      }
    }

    draw() {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
    }
  }

  // 初始化气泡
  for (let i = 0; i < BUBBLE_COUNT; i++) {
    bubbles.push(new Bubble());
  }

  // 统一渲染循环
  function animate() {
    // 每一帧彻底清空画布,保持透明度
    ctx.clearRect(0, 0, bgCanvas.width, bgCanvas.height);

    bubbles.forEach(b => {
      b.update();
      b.draw();
    });

    requestAnimationFrame(animate);
  }

  animate();
})();
毛玻璃效果
//毛玻璃效果
(function () {
  // ── 可调参数 ──────────────────────────
  const BLUR      = 12;    // 模糊半径 px,越大越"磨砂"
  const SATURATE  = 150;   // 提色 %,玻璃后面颜色更鲜活
  const ALPHA_L   = 0.25;  // 浅色模式背景不透明度(越小越透)
  const ALPHA_D   = 0.55;  // 暗色模式背景不透明度
  // ─────────────────────────────────────

  // 需要毛玻璃的容器(与原主题真实类名一致)
  const targets = [
    '.site-header', '.nav__sub',
    '.post', '.sidebar .widget',
    '.widget--toc', '.widget--toc.is-fixed', '.waxy-toc-float-panel',
    '.blog-stats__item', '.post-stats__item',
    '.about-author', '.empty-state',
    '.post-nav__item', '.breadcrumb',
    '.waxy-drawer__nav', '.page-404__card'
  ].join(',\n');

  const css = `
/* ── 毛玻璃质感覆盖(外挂,不改原文件)───────── */
${targets} {
  /* 半透明底色,让 backdrop-filter 有东西可透 */
  background: rgba(255, 255, 255, ${ALPHA_L}) !important;
  -webkit-backdrop-filter: blur(${BLUR}px) saturate(${SATURATE}%);
  backdrop-filter: blur(${BLUR}px) saturate(${SATURATE}%);
  /* 顶部一条极淡高光,模拟玻璃边缘反光 */
  border: 1px solid rgba(255, 255, 255, 0.45);
}

/* 暗色模式:换深色半透明底 + 更弱的高光边 */
html.dark ${targets.split(',\n').join(',\nhtml.dark ')} {
  background: rgba(36, 37, 38, ${ALPHA_D}) !important;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
`;

  const style = document.createElement('style');
  style.id = 'waxy-glass-override';
  style.textContent = css;
  document.head.appendChild(style);
})();