Greasy Fork

Greasy Fork is available in English.

Webpage Background Adjuster

调整网页下方背景的透明度、颜色遮罩、模糊度,并支持上传本地图片作为背景。/n Adjust the transparency, color overlay, and blur of the webpage's lower background, and support uploading local images as the background.

当前为 2025-03-05 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Webpage Background Adjuster
// @namespace    http://tampermonkey.net/
// @version      1.59
// @description  调整网页下方背景的透明度、颜色遮罩、模糊度,并支持上传本地图片作为背景。/n Adjust the transparency, color overlay, and blur of the webpage's lower background, and support uploading local images as the background.
// @author       Grey333
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    // 默认设置,去掉 enabled 属性
    const defaultSettings = {
        transparency: 1, // 滑块默认最高,背景最透明
        blur: 0,
        overlayColor: 'transparent',
        overlayOpacity: 0, // 默认最小百分比,遮罩最不透明
        forceMode: false // 强制模式默认关闭
    };

    // 按域名加载设置
    const domainKey = `settings_${location.hostname}`;
    let settings = JSON.parse(GM_getValue(domainKey, JSON.stringify(defaultSettings)));

    // 创建样式元素
    const style = document.createElement('style');
    style.id = 'background-adjuster-style';
    document.head.appendChild(style);

    // 设置初始 CSS 变量,反转遮罩透明度逻辑
    function applySettings() {
        document.body.style.setProperty('--base-transparency', 1 - settings.transparency);
        document.body.style.setProperty('--base-blur', settings.blur === 0 ? 'none' : `blur(${settings.blur}px)`);
        document.body.style.setProperty('--overlay-color', settings.overlayColor);
        document.body.style.setProperty('--overlay-opacity', 1 - settings.overlayOpacity); // 反转透明度
    }

    // 添加默认白色背景层
    const bgLayer = document.createElement('div');
    bgLayer.id = 'background-layer';
    bgLayer.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        z-index: -2;
        background: #ffffff;
        opacity: var(--base-transparency);
        filter: var(--base-blur);
    `;
    document.body.insertBefore(bgLayer, document.body.firstChild);

    // 添加颜色遮罩层
    const overlayLayer = document.createElement('div');
    overlayLayer.id = 'overlay-layer';
    overlayLayer.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        z-index: -1;
        background: var(--overlay-color);
        opacity: var(--overlay-opacity);
    `;
    document.body.insertBefore(overlayLayer, document.body.firstChild.nextSibling);

    // 添加优化后的 CSS 样式
    style.textContent = `
        body {
            position: relative;
            background: transparent !important;
        }
        #background-layer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            z-index: -2;
            opacity: var(--base-transparency);
            filter: var(--base-blur);
        }
        #overlay-layer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            z-index: -1;
            background: var(--overlay-color);
            opacity: var(--overlay-opacity);
        }
        body > *:not(#background-layer):not(#overlay-layer):not(#bg-adjuster-panel) {
            position: relative;
            z-index: 0;
        }
        #bg-adjuster-panel {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: #fafafa;
            border: none;
            padding: 25px;
            border-radius: 15px;
            box-shadow: 0 8px 25px rgba(0,0,0,0.2);
            z-index: 10000;
            display: none;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
            width: 300px;
            max-height: 85vh;
            overflow-y: auto;
            color: #333;
        }
        #bg-adjuster-panel label {
            display: flex;
            align-items: center;
            margin: 15px 0;
            font-size: 14px;
            color: #333;
        }
        #bg-adjuster-panel input[type="range"] {
            flex: 1;
            margin: 0 10px;
            height: 10px;
            border-radius: 8px;
            position: relative;
            outline: none;
            cursor: pointer;
            appearance: none;
        }
        #bg-adjuster-panel input[type="range"]::-webkit-slider-runnable-track {
            height: 10px;
            border-radius: 8px;
        }
        #bg-adjuster-panel input[type="range"]::-moz-range-track {
            height: 10px;
            border-radius: 8px;
        }
        #bg-adjuster-panel input[type="range"]::-webkit-slider-thumb {
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            border: 2px solid #fff;
            cursor: pointer;
            box-shadow: 0 3px 8px rgba(0,0,0,0.2);
            margin-top: -5px;
        }
        #bg-adjuster-panel input[type="range"]::-moz-range-thumb {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            border: 2px solid #fff;
            cursor: pointer;
            box-shadow: 0 3px 8px rgba(0,0,0,0.2);
        }
        #bg-adjuster-panel .percentage {
            width: 40px;
            text-align: right;
            font-size: 12px;
            color: #666;
        }
        #bg-adjuster-panel .color-btn {
            width: 26px;
            height: 26px;
            border-radius: 50%;
            border: 2px solid #ddd;
            cursor: pointer;
            margin-right: 10px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        #bg-adjuster-panel .color-btn:hover {
            transform: scale(1.15);
            box-shadow: 0 0 6px rgba(0,0,0,0.3);
        }
        #bg-adjuster-panel .color-btn:active {
            transform: scale(1.05);
            box-shadow: 0 0 8px rgba(0,0,0,0.4);
        }
        #bg-adjuster-panel #custom-color {
            width: 40px;
            height: 40px;
            padding: 0;
            border: 2px solid #ddd;
            border-radius: 12px;
            cursor: pointer;
            margin-left: auto;
            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
        }
        #bg-adjuster-panel button {
            padding: 8px 14px;
            cursor: pointer;
            border-radius: 10px;
            border: none;
            font-size: 14px;
            transition: background 0.2s;
        }
        #bg-image-label {
            display: block;
            margin: 15px 0;
            font-size: 14px;
        }
        #bg-image-label input[type="file"] {
            width: 100%;
            font-size: 12px;
            margin-top: 8px;
            padding: 6px;
            border: 1px solid #ddd;
            border-radius: 8px;
            background: #fff;
            color: #333;
        }
        #overlay-opacity-section {
            display: none;
        }
        #toggle-container {
            position: absolute;
            top: 15px;
            right: 15px;
            display: flex;
            align-items: center;
        }
        #force-mode-label {
            font-size: 12px;
            color: #333;
        }
    `;

    // 创建 UI 面板
    const panel = document.createElement('div');
    panel.id = 'bg-adjuster-panel';
    document.body.appendChild(panel);

    // UI 面板内容,去掉启用开关
    panel.innerHTML = `
        <h3 style="margin: 20px 0; font-size: 16px; text-align: center; color: #333;">背景调节器</h3>
        <label>透明度: <input type="range" min="0" max="1" step="0.01" id="transparency-slider" value="${settings.transparency}"><span class="percentage">${Math.round(settings.transparency * 100)}%</span></label>
        <label>模糊度: <input type="range" min="0" max="20" step="1" id="blur-slider" value="${settings.blur}"><span class="percentage">${Math.round((settings.blur / 20) * 100)}%</span></label>
        <div id="color-overlay-section">
            <label style="display: flex; align-items: center;">颜色遮罩:
                <button class="color-btn" id="none-btn" title="无"></button>
                <button class="color-btn" id="yellow-btn" title="黄色"></button>
                <button class="color-btn" id="green-btn" title="绿色"></button>
                <input type="color" id="custom-color" value="${settings.overlayColor === 'transparent' ? '#ffffff' : settings.overlayColor}" title="自定义颜色">
            </label>
        </div>
        <div id="overlay-opacity-section">
            <label id="overlay-opacity-label">遮罩透明度: <input type="range" min="0" max="1" step="0.01" id="overlay-opacity" value="${settings.overlayOpacity}"><span class="percentage">${Math.round(settings.overlayOpacity * 100)}%</span></label>
        </div>
        <label id="bg-image-label">背景图片:<input type="file" id="bg-image-input" accept="image/*"></label>
        <label style="display: flex; align-items: center;">强制模式:
            <input type="checkbox" id="force-mode-switch" ${settings.forceMode ? 'checked' : ''}>
        </label>
        <button id="reset-btn" style="width: 100%; margin-top: 15px;">重置</button>
        <button id="close-btn" style="width: 100%; margin-top: 10px;">关闭</button>
    `;

    // 获取 UI 元素
    const transparencySlider = document.getElementById('transparency-slider');
    const blurSlider = document.getElementById('blur-slider');
    const noneBtn = document.getElementById('none-btn');
    const yellowBtn = document.getElementById('yellow-btn');
    const greenBtn = document.getElementById('green-btn');
    const customColor = document.getElementById('custom-color');
    const overlayOpacity = document.getElementById('overlay-opacity');
    const overlayOpacitySection = document.getElementById('overlay-opacity-section');
    const bgImageInput = document.getElementById('bg-image-input');
    const resetBtn = document.getElementById('reset-btn');
    const closeBtn = document.getElementById('close-btn');
    const forceModeSwitch = document.getElementById('force-mode-switch');
    const backgroundLayer = document.getElementById('background-layer');
    const overlayLayerElement = document.getElementById('overlay-layer');
    const transparencyPercentage = transparencySlider.nextElementSibling;
    const blurPercentage = blurSlider.nextElementSibling;
    const overlayOpacityPercentage = overlayOpacity.nextElementSibling;

    // 更新设置和 CSS 变量的函数,反转遮罩透明度逻辑
    function updateSettings() {
        settings.transparency = parseFloat(transparencySlider.value);
        settings.blur = parseInt(blurSlider.value);
        settings.overlayColor = customColor.value === '#ffffff' && overlayOpacity.value == 0 ? 'transparent' : customColor.value;
        settings.overlayOpacity = parseFloat(overlayOpacity.value);
        settings.forceMode = forceModeSwitch.checked;

        applySettings();
        backgroundLayer.style.display = 'block';
        overlayLayerElement.style.display = 'block';
        document.body.style.setProperty('background', 'transparent', 'important');

        if (settings.forceMode) {
            // 强制模式下的内联样式
            forceModeSwitch.style.setProperty('background', forceModeSwitch.checked ? '#4a90e2' : '#999', 'important');
            noneBtn.style.setProperty('background', 'transparent', 'important');
            noneBtn.style.setProperty('border', '2px dashed #ccc', 'important');
            yellowBtn.style.setProperty('background', '#ffff00', 'important');
            greenBtn.style.setProperty('background', '#00ff00', 'important');
            resetBtn.style.setProperty('background', '#ff3b30', 'important');
            resetBtn.style.setProperty('color', 'white', 'important');
            closeBtn.style.setProperty('background', '#4a90e2', 'important');
            closeBtn.style.setProperty('color', 'white', 'important');
            transparencySlider.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${settings.transparency * 100}%, #e0e0e0 ${settings.transparency * 100}%)`, 'important');
            blurSlider.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${(settings.blur / 20) * 100}%, #e0e0e0 ${(settings.blur / 20) * 100}%)`, 'important');
            overlayOpacity.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${settings.overlayOpacity * 100}%, #e0e0e0 ${settings.overlayOpacity * 100}%)`, 'important');

            style.textContent += `
                body *:not(#bg-adjuster-panel):not(#background-layer):not(#overlay-layer) {
                    background-color: transparent !important;
                    background-image: none !important;
                }
            `;
        } else {
            // 非强制模式下的内联样式恢复
            forceModeSwitch.style.setProperty('background', forceModeSwitch.checked ? '#4a90e2' : '#999', 'important');
            noneBtn.style.setProperty('background', 'transparent', 'important');
            noneBtn.style.setProperty('border', '2px dashed #ccc', 'important');
            yellowBtn.style.setProperty('background', '#ffff00', 'important');
            greenBtn.style.setProperty('background', '#00ff00', 'important');
            resetBtn.style.setProperty('background', '#ff3b30', 'important');
            resetBtn.style.setProperty('color', 'white', 'important');
            closeBtn.style.setProperty('background', '#4a90e2', 'important');
            closeBtn.style.setProperty('color', 'white', 'important');
            transparencySlider.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${settings.transparency * 100}%, #e0e0e0 ${settings.transparency * 100}%)`, 'important');
            blurSlider.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${(settings.blur / 20) * 100}%, #e0e0e0 ${(settings.blur / 20) * 100}%)`, 'important');
            overlayOpacity.style.setProperty('background', `linear-gradient(to right, #4a90e2 ${settings.overlayOpacity * 100}%, #e0e0e0 ${settings.overlayOpacity * 100}%)`, 'important');

            style.textContent = style.textContent.replace(/body \*:not\(#bg-adjuster-panel\):not\(#background-layer\):not\(#overlay-layer\) {[^}]*}/g, '');
        }

        // 动态显示遮罩透明度进度条
        overlayOpacitySection.style.display = settings.overlayColor === 'transparent' ? 'none' : 'block';

        GM_setValue(domainKey, JSON.stringify(settings)); // 按域名保存设置
        transparencyPercentage.textContent = `${Math.round(settings.transparency * 100)}%`;
        blurPercentage.textContent = `${Math.round((settings.blur / 20) * 100)}%`;
        overlayOpacityPercentage.textContent = `${Math.round(settings.overlayOpacity * 100)}%`;
    }

    // 为开关和滑块添加事件监听(移除 toggleSwitch 相关)
    forceModeSwitch.addEventListener('change', updateSettings);
    transparencySlider.addEventListener('input', updateSettings);
    blurSlider.addEventListener('input', updateSettings);
    overlayOpacity.addEventListener('input', updateSettings);
    customColor.addEventListener('change', updateSettings);

    // 为颜色按钮添加事件监听
    noneBtn.addEventListener('click', () => {
        customColor.value = '#ffffff';
        overlayOpacity.value = 0; // 默认最小百分比
        updateSettings();
    });
    yellowBtn.addEventListener('click', () => {
        customColor.value = '#ffff00';
        if (settings.overlayOpacity === 0) overlayOpacity.value = 0; // 保持最小百分比
        updateSettings();
    });
    greenBtn.addEventListener('click', () => {
        customColor.value = '#00ff00';
        if (settings.overlayOpacity === 0) overlayOpacity.value = 0; // 保持最小百分比
        updateSettings();
    });

    // 处理背景图片上传
    bgImageInput.addEventListener('change', function() {
        const file = this.files[0];
        if (file) {
            const reader = new FileReader();
            reader.onload = function(e) {
                backgroundLayer.style.backgroundImage = `url(${e.target.result})`;
                backgroundLayer.style.backgroundSize = 'cover';
                backgroundLayer.style.backgroundRepeat = 'no-repeat';
                backgroundLayer.style.backgroundColor = 'transparent';
                updateSettings(); // 确保上传后更新样式
            };
            reader.readAsDataURL(file);
        }
    });

    // 重置按钮功能
    resetBtn.addEventListener('click', () => {
        settings = Object.assign({}, defaultSettings);
        settings.forceMode = forceModeSwitch.checked;
        transparencySlider.value = settings.transparency;
        blurSlider.value = settings.blur;
        customColor.value = '#ffffff';
        overlayOpacity.value = 0; // 重置为最小百分比
        document.body.style.setProperty('--base-transparency', 1 - settings.transparency);
        document.body.style.setProperty('--base-blur', 'none');
        document.body.style.setProperty('--overlay-color', 'transparent');
        document.body.style.setProperty('--overlay-opacity', 1 - settings.overlayOpacity); // 反转透明度
        backgroundLayer.style.backgroundImage = 'none';
        backgroundLayer.style.backgroundColor = '#ffffff';
        GM_setValue(domainKey, JSON.stringify(settings)); // 按域名保存设置
        transparencyPercentage.textContent = `${Math.round(settings.transparency * 100)}%`;
        blurPercentage.textContent = `${Math.round((settings.blur / 20) * 100)}%`;
        overlayOpacityPercentage.textContent = `${Math.round(settings.overlayOpacity * 100)}%`;
        updateSettings();
    });

    // 关闭面板
    closeBtn.addEventListener('click', () => {
        panel.style.display = 'none';
    });

    // 点击面板外关闭
    document.addEventListener('click', (e) => {
        if (!panel.contains(e.target) && panel.style.display === 'block') {
            panel.style.display = 'none';
        }
    });

    // 防止面板内部点击冒泡到外部关闭
    panel.addEventListener('click', (e) => {
        e.stopPropagation();
    });

    // Tampermonkey 菜单选项
    GM_registerMenuCommand('打开背景调节器', () => {
        panel.style.display = 'block';
    });

    // 初始化设置
    updateSettings(); // 直接调用 updateSettings,始终启用
})();