Greasy Fork

Greasy Fork is available in English.

Webpage Background Adjuster

调整网页背景的透明度、颜色遮罩、模糊度,并支持上传本地图片作为背景。按钮位置可通过菜单选择,支持贴边效果。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Webpage Background Adjuster
// @namespace    http://tampermonkey.net/
// @version      1.32
// @description  调整网页背景的透明度、颜色遮罩、模糊度,并支持上传本地图片作为背景。按钮位置可通过菜单选择,支持贴边效果。
// @author       Grey333
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    // 默认设置
    const defaultSettings = {
        transparency: 1,
        blur: 0,
        overlayColor: 'transparent',
        overlayOpacity: 0,
        togglePosition: 'right-bottom', // 默认右下
        toggleOffset: 10 // 默认偏移量 10px
    };

    // 加载保存的设置
    let settings = JSON.parse(GM_getValue('settings', JSON.stringify(defaultSettings)));

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

    // 设置初始 CSS 变量
    document.body.style.setProperty('--transparency', settings.transparency);
    document.body.style.setProperty('--blur', settings.blur === 0 ? 'none' : `blur(${settings.blur}px)`);
    document.body.style.setProperty('--overlay-color', settings.overlayColor);
    document.body.style.setProperty('--overlay-opacity', settings.overlayOpacity);

    // 添加优化后的 CSS 样式
    style.textContent = `
        body::before {
            content: "";
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            z-index: -2;
            background: inherit;
            opacity: var(--transparency);
            filter: var(--blur);
        }
        body::after {
            content: "";
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            z-index: -1;
            background: var(--overlay-color);
            opacity: var(--overlay-opacity);
        }
        body {
            background: transparent !important;
        }
        #bg-adjuster-panel {
            position: fixed;
            top: 60px;
            right: 10px;
            background: rgba(255, 255, 255, 0.95);
            border: none;
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 6px 20px rgba(0,0,0,0.15);
            z-index: 9999;
            display: none;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
            width: 280px;
            max-height: 80vh;
            overflow-y: auto;
        }
        #bg-adjuster-toggle {
            position: fixed;
            right: -10px; /* 默认贴边,只显示一半 */
            z-index: 10000;
            background: rgba(255, 255, 255, 0.3);
            backdrop-filter: blur(5px);
            border: none;
            padding: 10px;
            cursor: pointer;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            transition: right 0.3s ease;
        }
        #bg-adjuster-toggle:hover {
            right: 10px !important; /* 鼠标悬停时完全显示,强制覆盖 */
        }
        #bg-adjuster-toggle::before {
            content: "🎨";
            font-size: 15px;
        }
        #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: 5px;
            background: #e0e0e0;
            position: relative;
            outline: none;
            cursor: pointer;
            appearance: none;
        }
        #bg-adjuster-panel input[type="range"]::-webkit-slider-runnable-track {
            height: 10px;
            border-radius: 5px;
        }
        #bg-adjuster-panel input[type="range"]::-moz-range-track {
            height: 10px;
            border-radius: 5px;
        }
        #bg-adjuster-panel input[type="range"]::-webkit-slider-thumb {
            appearance: none;
            width: 18px;
            height: 18px;
            background: linear-gradient(135deg, #4a90e2, #357abd);
            border-radius: 50%;
            border: 2px solid #fff;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(0,0,0,0.2);
            margin-top: -4px;
        }
        #bg-adjuster-panel input[type="range"]::-moz-range-thumb {
            width: 18px;
            height: 18px;
            background: linear-gradient(135deg, #4a90e2, #357abd);
            border-radius: 50%;
            border: 2px solid #fff;
            cursor: pointer;
            box-shadow: 0 2px 6px 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: 24px;
            height: 24px;
            border-radius: 50%;
            border: 2px solid #ddd;
            cursor: pointer;
            margin-right: 8px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        #bg-adjuster-panel .color-btn:hover {
            transform: scale(1.2);
            box-shadow: 0 0 4px rgba(0,0,0,0.3);
        }
        #bg-adjuster-panel .color-btn:active {
            transform: scale(1.1);
            box-shadow: 0 0 6px rgba(0,0,0,0.4);
        }
        #bg-adjuster-panel #none-btn {
            background: transparent;
            border: 2px dashed #ccc;
        }
        #bg-adjuster-panel #yellow-btn {
            background: #ffff00;
        }
        #bg-adjuster-panel #green-btn {
            background: #00ff00;
        }
        #bg-adjuster-panel #custom-color {
            width: 40px;
            height: 40px;
            padding: 0;
            border: 2px solid #ddd;
            border-radius: 8px;
            cursor: pointer;
            margin-left: auto;
        }
        #bg-adjuster-panel button {
            padding: 6px 12px;
            cursor: pointer;
            border-radius: 8px;
            border: none;
            background: #f0f0f0;
            font-size: 12px;
            transition: background 0.2s;
        }
        #bg-adjuster-panel button:hover {
            background: #e0e0e0;
        }
        #bg-adjuster-panel #reset-btn {
            background: #ff3b30;
            color: white;
        }
        #bg-adjuster-panel #reset-btn:hover {
            background: #e6392e;
        }
        #bg-image-label {
            display: block;
            margin: 15px 0;
            font-size: 14px;
            color: #333;
            white-space: nowrap;
        }
        #bg-image-label input[type="file"] {
            width: 100%;
            font-size: 12px;
            margin-top: 5px;
        }
    `;

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

    // UI 面板内容
    panel.innerHTML = `
        <h3 style="margin: 0 0 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>
        <button id="reset-btn" style="width: 100%; margin-top: 15px;">重置</button>
    `;

    // 创建切换按钮
    const toggleBtn = document.createElement('div');
    toggleBtn.id = 'bg-adjuster-toggle';
    document.body.appendChild(toggleBtn);

    // 切换面板显示/隐藏
    toggleBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
    });

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

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

    // 获取 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 overlayOpacityLabel = document.getElementById('overlay-opacity-label');
    const bgImageInput = document.getElementById('bg-image-input');
    const resetBtn = document.getElementById('reset-btn');
    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);
        document.body.style.setProperty('--transparency', settings.transparency);
        document.body.style.setProperty('--blur', settings.blur === 0 ? 'none' : `blur(${settings.blur}px)`);
        document.body.style.setProperty('--overlay-color', settings.overlayColor);
        document.body.style.setProperty('--overlay-opacity', settings.overlayOpacity);
        GM_setValue('settings', 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)}%`;
        transparencySlider.style.background = `linear-gradient(to right, #4a90e2 ${settings.transparency * 100}%, #e0e0e0 ${settings.transparency * 100}%)`;
        blurSlider.style.background = `linear-gradient(to right, #4a90e2 ${(settings.blur / 20) * 100}%, #e0e0e0 ${(settings.blur / 20) * 100}%)`;
        overlayOpacity.style.background = `linear-gradient(to right, #4a90e2 ${settings.overlayOpacity * 100}%, #e0e0e0 ${settings.overlayOpacity * 100}%)`;
    }

    // 为进度条添加事件监听并阻止冒泡
    transparencySlider.addEventListener('input', (e) => {
        e.stopPropagation();
        updateSettings();
    });
    blurSlider.addEventListener('input', (e) => {
        e.stopPropagation();
        updateSettings();
    });
    overlayOpacity.addEventListener('input', (e) => {
        e.stopPropagation();
        updateSettings();
    });
    overlayOpacityLabel.addEventListener('click', (e) => e.stopPropagation());
    customColor.addEventListener('change', updateSettings);

    // 为颜色按钮添加事件监听
    noneBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        customColor.value = '#ffffff';
        overlayOpacity.value = 0;
        updateSettings();
    });
    yellowBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        customColor.value = '#ffff00';
        if (settings.overlayOpacity === 0) overlayOpacity.value = 0.5;
        updateSettings();
    });
    greenBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        customColor.value = '#00ff00';
        if (settings.overlayOpacity === 0) overlayOpacity.value = 0.5;
        updateSettings();
    });

    // 处理背景图片上传
    bgImageInput.addEventListener('change', function() {
        const file = this.files[0];
        if (file) {
            const reader = new FileReader();
            reader.onload = function(e) {
                document.body.style.setProperty('--original-bg-image', `url(${e.target.result})`);
                style.textContent += `
                    body::before {
                        background-image: var(--original-bg-image);
                        background-size: cover;
                        background-repeat: no-repeat;
                    }
                `;
            };
            reader.readAsDataURL(file);
        }
    });

    // 重置按钮功能
    resetBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        settings = Object.assign({}, defaultSettings);
        transparencySlider.value = settings.transparency;
        blurSlider.value = settings.blur;
        customColor.value = '#ffffff';
        overlayOpacity.value = 0;
        document.body.style.setProperty('--transparency', settings.transparency);
        document.body.style.setProperty('--blur', 'none');
        document.body.style.setProperty('--overlay-color', 'transparent');
        document.body.style.setProperty('--overlay-opacity', 0);
        document.body.style.removeProperty('--original-bg-image');
        applyTogglePosition();
        GM_setValue('settings', JSON.stringify(settings));
        style.textContent = style.textContent.replace(/body::before\s*{\s*background-image:[^}]*;\s*background-size:[^}]*;\s*background-repeat:[^}]*;\s*}/g, '');
        transparencyPercentage.textContent = `${Math.round(settings.transparency * 100)}%`;
        blurPercentage.textContent = `${Math.round((settings.blur / 20) * 100)}%`;
        overlayOpacityPercentage.textContent = `${Math.round(settings.overlayOpacity * 100)}%`;
        updateSettings();
    });

    // 应用按钮位置
    function applyTogglePosition() {
        // 重置所有位置相关样式
        toggleBtn.style.right = '-20px'; // 默认贴边
        toggleBtn.style.left = 'auto';
        toggleBtn.style.top = 'auto';
        toggleBtn.style.bottom = 'auto';
        toggleBtn.style.transform = 'none';

        // 根据 togglePosition 应用位置
        switch (settings.togglePosition) {
            case 'right-top':
                toggleBtn.style.top = `${settings.toggleOffset}px`;
                break;
            case 'right-middle':
                toggleBtn.style.top = '50%';
                toggleBtn.style.transform = 'translateY(-50%)';
                break;
            case 'right-bottom':
                toggleBtn.style.bottom = `${settings.toggleOffset}px`;
                break;
            default:
                toggleBtn.style.top = '10px'; // 防止无效值
        }
    }

    // Tampermonkey 菜单选项
    console.log('Registering menu commands...');
    GM_registerMenuCommand('Set Position: Top Right', () => {
        console.log('Selected Top Right');
        settings.togglePosition = 'right-top';
        settings.toggleOffset = 10;
        applyTogglePosition();
        GM_setValue('settings', JSON.stringify(settings));
    });

    GM_registerMenuCommand('Set Position: Middle Right', () => {
        console.log('Selected Middle Right');
        settings.togglePosition = 'right-middle';
        settings.toggleOffset = 0;
        applyTogglePosition();
        GM_setValue('settings', JSON.stringify(settings));
    });

    GM_registerMenuCommand('Set Position: Bottom Right', () => {
        console.log('Selected Bottom Right');
        settings.togglePosition = 'right-bottom';
        settings.toggleOffset = 10;
        applyTogglePosition();
        GM_setValue('settings', JSON.stringify(settings));
    });

    GM_registerMenuCommand('Set Vertical Offset (px)', () => {
        console.log('Setting offset');
        const offset = prompt('Enter vertical offset (px, 0-100):', settings.toggleOffset);
        const parsedOffset = parseInt(offset);
        if (!isNaN(parsedOffset) && parsedOffset >= 0 && parsedOffset <= 100) {
            settings.toggleOffset = parsedOffset;
            applyTogglePosition();
            GM_setValue('settings', JSON.stringify(settings));
        } else {
            alert('Please enter a valid number (0-100)');
        }
    });

    // 初始化设置
    applyTogglePosition();
    updateSettings();
    console.log('Initialized with position:', settings.togglePosition, 'offset:', settings.toggleOffset);
})();