// ==UserScript==
// @name 网页背景调节器(Webpage Background Adjuster)
// @namespace http://tampermonkey.net/
// @version 1.60
// @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';
// 默认设置
const defaultSettings = {
transparency: 1, // 滑块默认最高,背景最透明
blur: 0,
overlayColor: 'transparent',
overlayOpacity: 0, // 默认最小百分比,遮罩最不透明
forceMode: false, // 强制模式默认关闭
disableOnThisPage: false, // 默认生效
backgroundImage: null // 默认无背景图片
};
// 按域名加载设置
const domainKey = `settings_${location.hostname}`;
let settings = JSON.parse(GM_getValue(domainKey, JSON.stringify(defaultSettings)));
// 注册油猴菜单项(无论是否禁用都执行)
GM_registerMenuCommand(settings.disableOnThisPage ? '恢复脚本在此页面生效' : '在此页面禁用脚本', () => {
settings.disableOnThisPage = !settings.disableOnThisPage;
GM_setValue(domainKey, JSON.stringify(settings));
location.reload(); // 刷新页面以应用更改
});
GM_registerMenuCommand('打开背景调节器', () => {
if (!settings.disableOnThisPage) {
panel.style.display = 'block';
}
});
// 如果该页面不生效,直接返回,不执行后续逻辑
if (settings.disableOnThisPage) {
return;
}
// 创建样式元素
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);
pointer-events: none; /* 确保鼠标事件穿透 */
`;
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);
pointer-events: none; /* 确保鼠标事件穿透 */
`;
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);
pointer-events: none;
}
#overlay-layer {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
background: var(--overlay-color);
opacity: var(--overlay-opacity);
pointer-events: none;
}
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;
}
#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.backgroundImage) {
backgroundLayer.style.backgroundImage = `url(${settings.backgroundImage})`;
backgroundLayer.style.backgroundSize = 'cover';
backgroundLayer.style.backgroundRepeat = 'no-repeat';
backgroundLayer.style.backgroundColor = 'transparent';
} else {
backgroundLayer.style.backgroundImage = 'none';
backgroundLayer.style.backgroundColor = '#ffffff';
}
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):not(input):not(button):not(select):not(textarea):not(a) {
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\):not\(input\):not\(button\):not\(select\):not\(textarea\):not\(a\) {[^}]*}/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)}%`;
}
// 为开关和滑块添加事件监听
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) {
settings.backgroundImage = e.target.result; // 保存图片 Data URL
backgroundLayer.style.backgroundImage = `url(${settings.backgroundImage})`;
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;
// 不重置 disableOnThisPage,让它保持菜单控制
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();
});
// 初始化设置
updateSettings(); // 直接调用 updateSettings
})();