网页颜色自定义油猴脚本
一个轻量级的 Tampermonkey 脚本,允许你在任意网页上自定义背景色、文字颜色和链接颜色,并持久化保存设置。
脚本代码
javascript
// ==UserScript==
// @name 网页颜色自定义(带主题)
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 自定义网页背景色和文字颜色,支持预设主题
// @author 元宝
// @match *://*/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 默认颜色设置
const defaultColors = {
bgColor: '#ffffff',
textColor: '#000000',
linkColor: '#0000ee'
};
// 预设主题
const colorThemes = {
'default': {
name: '默认主题',
bgColor: '#ffffff',
textColor: '#000000',
linkColor: '#0000ee'
},
'dark': {
name: '暗黑模式',
bgColor: '#121212',
textColor: '#ffffff',
linkColor: '#bb86fc'
},
'dark-blue': {
name: '深蓝主题',
bgColor: '#0a192f',
textColor: '#ccd6f6',
linkColor: '#64ffda'
},
'eye-protect': {
name: '护眼模式',
bgColor: '#c7edcc',
textColor: '#000000',
linkColor: '#1890ff'
},
'sepia': {
name: '羊皮纸',
bgColor: '#f4ecd8',
textColor: '#5b4636',
linkColor: '#9c4a1a'
},
'terminal': {
name: '终端风格',
bgColor: '#000000',
textColor: '#00ff00',
linkColor: '#00ffff'
},
'github-dark': {
name: 'GitHub暗色',
bgColor: '#0d1117',
textColor: '#c9d1d9',
linkColor: '#58a6ff'
},
'solarized-light': {
name: 'Solarized浅色',
bgColor: '#fdf6e3',
textColor: '#657b83',
linkColor: '#268bd2'
},
'solarized-dark': {
name: 'Solarized深色',
bgColor: '#002b36',
textColor: '#839496',
linkColor: '#2aa198'
},
'midnight': {
name: '午夜蓝',
bgColor: '#191970',
textColor: '#e6e6fa',
linkColor: '#9370db'
},
'warm': {
name: '暖色调',
bgColor: '#fffaf0',
textColor: '#8b4513',
linkColor: '#cd853f'
}
};
// 从存储中获取颜色或使用默认值
let currentTheme = GM_getValue('currentTheme', 'default');
let bgColor = GM_getValue('bgColor', defaultColors.bgColor);
let textColor = GM_getValue('textColor', defaultColors.textColor);
let linkColor = GM_getValue('linkColor', defaultColors.linkColor);
// 更新当前主题的颜色
function updateColorsFromTheme(themeName) {
const theme = colorThemes[themeName];
if (theme) {
bgColor = theme.bgColor;
textColor = theme.textColor;
linkColor = theme.linkColor;
currentTheme = themeName;
// 更新输入框
document.getElementById('bgColorInput').value = bgColor;
document.getElementById('textColorInput').value = textColor;
document.getElementById('linkColorInput').value = linkColor;
// 更新预览
document.getElementById('bgPreview').style.backgroundColor = bgColor;
document.getElementById('textPreview').style.backgroundColor = textColor;
document.getElementById('linkPreview').style.backgroundColor = linkColor;
// 更新主题选择器
document.getElementById('themeSelect').value = themeName;
// 保存设置
GM_setValue('currentTheme', themeName);
GM_setValue('bgColor', bgColor);
GM_setValue('textColor', textColor);
GM_setValue('linkColor', linkColor);
// 应用颜色
applyColors();
}
}
// 添加自定义CSS样式
GM_addStyle(`
.color-customizer {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
background: rgba(255, 255, 255, 0.98);
border: 1px solid #ccc;
border-radius: 8px 0 0 8px;
padding: 15px;
box-shadow: -2px 0 10px rgba(0,0,0,0.1);
z-index: 999999;
min-width: 250px;
font-family: Arial, sans-serif;
max-height: 80vh;
overflow-y: auto;
}
.color-customizer h3 {
margin-top: 0;
font-size: 16px;
color: #333;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.color-control {
margin: 12px 0;
}
.color-control label {
display: block;
font-size: 12px;
margin-bottom: 5px;
color: #666;
font-weight: bold;
}
.color-preview {
width: 20px;
height: 20px;
border: 1px solid #ccc;
border-radius: 3px;
display: inline-block;
vertical-align: middle;
margin-right: 5px;
cursor: pointer;
}
.color-input {
width: calc(100% - 30px);
padding: 5px;
border: 1px solid #ddd;
border-radius: 3px;
font-size: 12px;
}
.theme-select {
width: 100%;
padding: 6px;
border: 1px solid #ddd;
border-radius: 4px;
background: white;
font-size: 12px;
margin-bottom: 10px;
}
.theme-select option {
padding: 5px;
}
.theme-preview {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 2px;
margin-right: 8px;
border: 1px solid #ddd;
}
.theme-item {
display: flex;
align-items: center;
padding: 3px 0;
}
.color-btn {
background: #4CAF50;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
margin-top: 5px;
width: calc(50% - 3px);
transition: background 0.3s;
}
.color-btn:hover {
background: #45a049;
}
.color-btn.reset {
background: #f44336;
}
.color-btn.reset:hover {
background: #da190b;
}
.toggle-btn {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
background: #4CAF50;
color: white;
border: none;
border-radius: 4px 0 0 4px;
padding: 8px 12px;
cursor: pointer;
z-index: 999998;
font-size: 12px;
box-shadow: -2px 0 5px rgba(0,0,0,0.1);
}
.toggle-btn:hover {
background: #45a049;
}
.button-group {
display: flex;
justify-content: space-between;
gap: 6px;
margin-top: 10px;
}
.theme-section {
margin: 15px 0;
padding: 10px;
background: #f9f9f9;
border-radius: 5px;
border-left: 3px solid #4CAF50;
}
.theme-section h4 {
margin: 0 0 8px 0;
font-size: 13px;
color: #333;
}
.quick-themes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-top: 5px;
}
.theme-btn {
padding: 6px 8px;
border: 1px solid #ddd;
background: white;
border-radius: 4px;
cursor: pointer;
font-size: 11px;
text-align: center;
transition: all 0.2s;
}
.theme-btn:hover {
background: #f0f0f0;
transform: translateY(-1px);
}
.theme-btn.active {
background: #4CAF50;
color: white;
border-color: #45a049;
}
.theme-name {
font-weight: bold;
}
`);
// 创建颜色自定义面板
function createColorPanel() {
const panel = document.createElement('div');
panel.className = 'color-customizer';
panel.innerHTML = `
<h3>🎨 网页颜色设置</h3>
<div class="theme-section">
<h4>预设主题</h4>
<select id="themeSelect" class="theme-select">
${Object.entries(colorThemes).map(([id, theme]) => `
<option value="${id}" ${id === currentTheme ? 'selected' : ''}>
${theme.name}
</option>
`).join('')}
</select>
<div class="quick-themes">
<button class="theme-btn ${currentTheme === 'dark' ? 'active' : ''}" data-theme="dark" style="background: linear-gradient(45deg, #121212 50%, #333 50%); color: white;">
暗黑
</button>
<button class="theme-btn ${currentTheme === 'eye-protect' ? 'active' : ''}" data-theme="eye-protect" style="background: #c7edcc; color: #000;">
护眼
</button>
<button class="theme-btn ${currentTheme === 'dark-blue' ? 'active' : ''}" data-theme="dark-blue" style="background: #0a192f; color: #ccd6f6;">
深蓝
</button>
<button class="theme-btn ${currentTheme === 'sepia' ? 'active' : ''}" data-theme="sepia" style="background: #f4ecd8; color: #5b4636;">
羊皮纸
</button>
</div>
</div>
<div class="color-control">
<label>背景颜色:</label>
<div class="color-preview" id="bgPreview" style="background-color: ${bgColor};"></div>
<input type="text" id="bgColorInput" class="color-input" value="${bgColor}" placeholder="#ffffff 或 rgb(255,255,255)">
</div>
<div class="color-control">
<label>文字颜色:</label>
<div class="color-preview" id="textPreview" style="background-color: ${textColor};"></div>
<input type="text" id="textColorInput" class="color-input" value="${textColor}" placeholder="#000000 或 rgb(0,0,0)">
</div>
<div class="color-control">
<label>链接颜色:</label>
<div class="color-preview" id="linkPreview" style="background-color: ${linkColor};"></div>
<input type="text" id="linkColorInput" class="color-input" value="${linkColor}" placeholder="#0000ee 或 rgb(0,0,238)">
</div>
<div class="button-group">
<button class="color-btn" id="applyColors">💾 保存并应用</button>
<button class="color-btn reset" id="resetColors">🔄 重置默认</button>
</div>
`;
return panel;
}
// 创建切换按钮
function createToggleButton() {
const toggleBtn = document.createElement('button');
toggleBtn.className = 'toggle-btn';
toggleBtn.textContent = '🎨 颜色';
toggleBtn.title = '显示/隐藏颜色设置面板';
return toggleBtn;
}
// 应用颜色到页面
function applyColors() {
const styleId = 'custom-colors-style';
let styleEl = document.getElementById(styleId);
if (!styleEl) {
styleEl = document.createElement('style');
styleEl.id = styleId;
document.head.appendChild(styleEl);
}
const css = `
body, div, section, article, main, header, footer, aside, nav {
background-color: ${bgColor} !important;
color: ${textColor} !important;
}
a, a:link, a:visited, a:hover, a:active {
color: ${linkColor} !important;
}
/* 处理一些特殊元素 */
input, textarea, select, button {
background-color: inherit !important;
color: ${textColor} !important;
}
/* 处理代码块和预格式文本 */
pre, code, kbd, samp {
background-color: inherit !important;
color: ${textColor} !important;
}
/* 处理表格 */
table, th, td {
background-color: inherit !important;
color: ${textColor} !important;
border-color: ${textColor}33 !important;
}
`;
styleEl.textContent = css;
// 保存到存储
GM_setValue('bgColor', bgColor);
GM_setValue('textColor', textColor);
GM_setValue('linkColor', linkColor);
// 检查是否匹配某个预设主题
let matchedTheme = 'default';
for (const [themeId, theme] of Object.entries(colorThemes)) {
if (theme.bgColor === bgColor && theme.textColor === textColor && theme.linkColor === linkColor) {
matchedTheme = themeId;
break;
}
}
if (matchedTheme !== currentTheme) {
currentTheme = matchedTheme;
GM_setValue('currentTheme', matchedTheme);
// 更新UI
const themeSelect = document.getElementById('themeSelect');
if (themeSelect) themeSelect.value = matchedTheme;
// 更新快速主题按钮状态
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.theme === matchedTheme) {
btn.classList.add('active');
}
});
}
}
// 重置颜色
function resetColors() {
updateColorsFromTheme('default');
}
// 初始化
function init() {
// 创建面板和按钮
const panel = createColorPanel();
const toggleBtn = createToggleButton();
document.body.appendChild(panel);
document.body.appendChild(toggleBtn);
// 应用初始颜色
setTimeout(applyColors, 100);
// 切换面板显示/隐藏
let panelVisible = true;
toggleBtn.addEventListener('click', () => {
panelVisible = !panelVisible;
panel.style.display = panelVisible ? 'block' : 'none';
toggleBtn.textContent = panelVisible ? '🎨 颜色' : '🎨';
});
// 主题选择器事件
document.getElementById('themeSelect').addEventListener('change', function(e) {
updateColorsFromTheme(e.target.value);
});
// 快速主题按钮事件
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.addEventListener('click', function() {
updateColorsFromTheme(this.dataset.theme);
});
});
// 颜色预览点击事件
const previews = ['bgPreview', 'textPreview', 'linkPreview'];
previews.forEach(previewId => {
const preview = document.getElementById(previewId);
preview.addEventListener('click', () => {
const colorInput = previewId.replace('Preview', 'Input');
const input = document.getElementById(colorInput);
// 创建一个临时的颜色选择器
const colorPicker = document.createElement('input');
colorPicker.type = 'color';
colorPicker.value = input.value;
colorPicker.style.position = 'fixed';
colorPicker.style.left = '-1000px';
document.body.appendChild(colorPicker);
colorPicker.click();
colorPicker.addEventListener('change', () => {
const newColor = colorPicker.value;
input.value = newColor;
preview.style.backgroundColor = newColor;
// 更新对应的颜色变量
if (previewId === 'bgPreview') bgColor = newColor;
if (previewId === 'textPreview') textColor = newColor;
if (previewId === 'linkPreview') linkColor = newColor;
// 标记为自定义主题
currentTheme = 'custom';
GM_setValue('currentTheme', 'custom');
document.getElementById('themeSelect').value = 'default'; // 选择默认,但实际上是自定义
document.querySelectorAll('.theme-btn').forEach(btn => btn.classList.remove('active'));
applyColors();
});
setTimeout(() => {
document.body.removeChild(colorPicker);
}, 100);
});
});
// 应用颜色按钮
document.getElementById('applyColors').addEventListener('click', () => {
bgColor = document.getElementById('bgColorInput').value;
textColor = document.getElementById('textColorInput').value;
linkColor = document.getElementById('linkColorInput').value;
document.getElementById('bgPreview').style.backgroundColor = bgColor;
document.getElementById('textPreview').style.backgroundColor = textColor;
document.getElementById('linkPreview').style.backgroundColor = linkColor;
// 标记为自定义主题
currentTheme = 'custom';
GM_setValue('currentTheme', 'custom');
document.getElementById('themeSelect').value = 'default'; // 选择默认,但实际上是自定义
document.querySelectorAll('.theme-btn').forEach(btn => btn.classList.remove('active'));
applyColors();
});
// 重置按钮
document.getElementById('resetColors').addEventListener('click', resetColors);
// 实时颜色输入更新
const colorInputs = ['bgColorInput', 'textColorInput', 'linkColorInput'];
colorInputs.forEach(inputId => {
const input = document.getElementById(inputId);
input.addEventListener('input', (e) => {
const previewId = inputId.replace('Input', 'Preview');
document.getElementById(previewId).style.backgroundColor = e.target.value;
// 标记为自定义主题
currentTheme = 'custom';
GM_setValue('currentTheme', 'custom');
document.getElementById('themeSelect').value = 'default';
document.querySelectorAll('.theme-btn').forEach(btn => btn.classList.remove('active'));
});
input.addEventListener('change', (e) => {
const previewId = inputId.replace('Input', 'Preview');
document.getElementById(previewId).style.backgroundColor = e.target.value;
});
});
// 按ESC键隐藏面板
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
panel.style.display = 'none';
toggleBtn.textContent = '🎨';
panelVisible = false;
}
});
}
// 等待页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();使用方法
安装
- 确保浏览器已安装 Tampermonkey 扩展
- 在 Tampermonkey 中新建脚本,将上述代码粘贴进去保存
- 刷新任意网页,页面右侧会出现一个绿色「颜色」按钮
操作说明
| 操作 | 说明 |
|---|---|
| 点击「颜色」按钮 | 显示/隐藏颜色设置面板 |
| 输入十六进制色值 | 直接在输入框填写颜色代码(如 #f5f5f5) |
| 点击色块预览 | 弹出系统原生颜色选择器,可视化选色 |
| 点击「应用颜色」 | 将当前设置应用到页面并保存 |
| 点击「重置默认」 | 恢复白底黑字蓝链接的默认配色 |
效果
- 设置即时生效,无需刷新页面
- 设置会自动保存(通过
GM_setValue),下次访问同一域名自动恢复 - 点击色块预览可调出系统颜色选择器,支持可视化选色
脚本逻辑详解
整体架构
脚本遵循「面板渲染 → 用户交互 → 样式注入 → 持久化存储」的线性流程:
用户打开网页
↓
脚本执行(@run-at document-end)
↓
读取 GM 存储中的颜色配置
↓
创建 UI 面板和切换按钮
↓
注入自定义 CSS 样式覆盖页面颜色
↓
等待用户操作(修改颜色 / 切换面板 / 重置)
↓
更新存储并重新注入样式核心模块说明
1. 存储模块(GM API)
利用 Tampermonkey 提供的 GM_getValue / GM_setValue 实现跨会话持久化:
GM_getValue('bgColor', '#ffffff')— 读取存储值,不存在则用默认值GM_setValue('bgColor', '#f0f0f0')— 保存新值,下次访问自动恢复
数据按域名隔离,不同网站可以有不同的颜色配置。
2. 样式注入模块
通过动态创建 <style> 标签注入 CSS:
javascript
function applyColors() {
const css = `
body, div, section, article, main {
background-color: ${bgColor} !important;
color: ${textColor} !important;
}
a, a:link, a:visited { color: ${linkColor} !important; }
`;
// 注入到 <head> 中
}使用 !important 确保覆盖页面原有样式。style 标签带 id="custom-colors-style",多次调用时复用同一标签,避免重复添加。
3. UI 交互模块
- 颜色面板:固定定位在页面右侧中部,半透明毛玻璃效果
- 切换按钮:点击显示/隐藏面板,点击时不遮挡页面内容
- 实时预览:输入框的
input事件会实时更新色块预览 - 颜色选择器:点击色块会创建一个隐藏的
<input type="color">元素,调起系统原生取色器
4. 选择器覆盖策略
脚本通过 CSS 选择器批量覆盖页面元素的颜色:
| 目标 | 选择器 |
|---|---|
| 主体背景与文字 | body, div, section, article, main, header, footer, aside, nav |
| 链接颜色 | a, a:link, a:visited, a:hover, a:active |
| 表单控件 | input, textarea, select, button(继承背景,用文字颜色) |
注意事项
- 部分网站使用内联样式或 Shadow DOM,脚本的
!important规则可能无法覆盖 @match *://*/*会匹配所有网页,如果只想在特定网站生效,可修改@match规则- 颜色值需使用合法的十六进制格式(如
#ffffff),脚本未做格式校验