Greasy Fork

Greasy Fork is available in English.

网页字体替换增强器

替换网页默认字体,默认为 MiSans、FZYouSong GBK 509R(方正悠宋)、Cascadia Mono。可根据需求修改脚本中的字体设置。使用前需确保已安装所需字体。

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         网页字体替换增强器
// @namespace    chNt6w8D6cVSQE93BSC8VS6QxNshGaSP9QcK82kruzbN5E4K2TJKxbNjpAXDfJKe
// @description  替换网页默认字体,默认为 MiSans、FZYouSong GBK 509R(方正悠宋)、Cascadia Mono。可根据需求修改脚本中的字体设置。使用前需确保已安装所需字体。
// @version      7
// @license      Apache License 2.0
// @author       Anonymous
// @compatible   firefox
// @compatible   safari
// @compatible   chrome
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==
(function () {
    "use strict";
    const defaultConfig = {
        sans_namespace: ["MiSans", "MiSans L3", ""],
        sans_latin: ["MiSans", "MiSans L3", ""],
        sans_simplified: ["MiSans", "MiSans L3", ""],
        sans_traditional: ["MiSans", "MiSans L3", ""],
        serif_namespace: ["FZYouSong GBK 509R", "Times New Roman", ""],
        serif_simplified: ["FZYouSong GBK 509R", "Times New Roman", ""],
        serif_traditional: ["FZYouSong GBK 509R", "Times New Roman", ""],
        mono_namespace: ["Cascadia Mono", "Arial", ""],
        mono: ["Cascadia Mono", "Arial", ""],
    };
    function loadConfig() {
        return {
            sans_namespace: GM_getValue("sans_namespace", defaultConfig.sans_namespace),
            sans_latin: GM_getValue("sans_latin", defaultConfig.sans_latin),
            serif_namespace: GM_getValue("serif_namespace", defaultConfig.serif_namespace),
            sans_simplified: GM_getValue("sans_simplified", defaultConfig.sans_simplified),
            sans_traditional: GM_getValue("sans_traditional", defaultConfig.sans_traditional),
            serif_simplified: GM_getValue("serif_simplified", defaultConfig.serif_simplified),
            serif_traditional: GM_getValue("serif_traditional", defaultConfig.serif_traditional),
            mono_namespace: GM_getValue("mono_namespace", defaultConfig.mono_namespace),
            mono: GM_getValue("mono", defaultConfig.mono),
        };
    }
    function saveConfig() {
        Object.keys(config).forEach(key => {
            GM_setValue(key, config[key]);
        });
    }
    function createConfigUI() {
        const overlay = document.createElement("div");
        overlay.style = `
            position: fixed;
            inset: 0;
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(5px); /* 高斯模糊 */
            display: grid;
            place-items: center;
            z-index: 999999;
            transition: opacity 0.3s;
        `;
        const panel = document.createElement("div");
        panel.style = `
            background: #ffffff; /* 白色背景 */
            border-radius: 16px;
            width: min(95vw, 800px); /* 确保最大宽度不超过屏幕宽度 */
            max-height: 90vh;
            overflow-y: auto; /* 垂直滚动条 */
            padding: 2rem;
            box-shadow: 0 10px 25px rgba(0,0,0,0.1); /* 柔和阴影 */
            color: #333333; /* 文字颜色 */
            font-family: MiSans, sans-serif;
            animation: slideIn 0.3s ease;
        `;
        const title = document.createElement("h2");
        title.textContent = "字体替换增强器 · 配置面板";
        title.style = `
            margin: 0 0 1.5rem;
            font-size: 1.5rem;
            text-align: center;
            color: #333333; /* 深灰色标题 */
            position: relative;
            padding-bottom: 0.5rem;
        `;
        const titleUnderline = document.createElement("div");
        titleUnderline.style = `
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 60px;
            height: 3px;
            background: linear-gradient(90deg, #4f46e5, #ec4899);
            border-radius: 1px;
        `;
        title.appendChild(titleUnderline);
        const createInputGroup = (type, label) => {
            const container = document.createElement("div");
            container.style.marginBottom = "1.5rem";
            const titleLabel = document.createElement("label");
            titleLabel.textContent = label;
            titleLabel.style = `
                display: block;
                margin-bottom: 0.75rem;
                font-weight: 600;
                color: #333333; /* 深灰色标签 */
                font-size: 1rem;
                position: relative;
                padding-left: 1.25rem;
            `;
            titleLabel.innerHTML += `
                <span style="
                    position: absolute;
                    left: 0;
                    top: 50%;
                    transform: translateY(-50%);
                    width: 4px;
                    height: 1rem;
                    background: linear-gradient(transparent, #4f46e5, transparent);
                    border-radius: 2px;
                "></span>
            `;
            const inputContainer = document.createElement("div");
            inputContainer.style = `
                display: grid;
                grid-template-columns: repeat(3, calc(33.33% - 10px)); /* 每个输入框占三分之一宽度,减去间距 */
                gap: 10px; /* 输入框之间的间距 */
            `;
            for (let i = 0; i < 3; i++) {
                const input = document.createElement("input");
                input.type = "text";
                input.value = config[type][i];
                input.dataset.type = type;
                input.dataset.index = i;
                input.placeholder = `备选字体 ${i + 1}`;
                input.style = `
                    width: 100%; /* 输入框占满网格单元 */
                    padding: 0.75rem 1rem;
                    border: 1px solid #cccccc;
                    border-radius: 8px;
                    font-size: 0.75rem;
                    color: #333333; /* 深灰色文字 */
                    background: #f9f9f9; /* 浅灰色背景 */
                    transition: all 0.2s;
                `;
                input.addEventListener('focus', () => {
                    input.style.borderColor = '#4f46e5';
                    input.style.boxShadow = '0 0 0 2px rgba(79,70,229,0.2)';
                });
                input.addEventListener('blur', () => {
                    input.style.borderColor = '#cccccc';
                    input.style.boxShadow = 'none';
                });
                inputContainer.appendChild(input);
            }
            container.appendChild(titleLabel);
            container.appendChild(inputContainer);
            return container;
        };
        const createButton = (text, bgColor, hoverColor) => {
            const btn = document.createElement("button");
            btn.textContent = text;
            btn.style = `
                width: 100%;
                padding: 0.75rem 1rem;
                background: ${bgColor};
                border: none;
                border-radius: 8px;
                color: white;
                font-weight: 600;
                cursor: pointer;
                transition: all 0.2s;
                margin: 0.5rem 0;
            `;
            btn.addEventListener('mouseover', () => btn.style.backgroundColor = hoverColor);
            btn.addEventListener('mouseout', () => btn.style.backgroundColor = bgColor);
            return btn;
        };
        const importExportSection = document.createElement("div");
        importExportSection.style.margin = "1.5rem 0";
        const buttonContainer = document.createElement("div");
        buttonContainer.style.display = "flex";
        buttonContainer.style.gap = "0.75rem";
        const importInput = document.createElement("input");
        importInput.type = "file";
        importInput.accept = ".json";
        importInput.style.display = "none";
        const importBtn = createButton("导入配置", "#4f46e5", "#4338ca");
        importBtn.onclick = () => importInput.click();
        importInput.onchange = async () => {
            try {
                const file = importInput.files[0];
                const content = await file.text();
                const importedConfig = JSON.parse(content);
                Object.assign(config, importedConfig);
                saveConfig();
                alert("配置已导入,请刷新页面生效");
                overlay.remove();
            } catch (e) {
                alert("导入失败:无效的配置文件");
            }
        };
        const exportBtn = createButton("导出配置", "#16a34a", "#15803d");
        exportBtn.onclick = () => {
            const blob = new Blob([JSON.stringify(config, null, 2)], {
                type: "application/json",
            });
            const url = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.href = url;
            a.download = "font-config.json";
            a.click();
            URL.revokeObjectURL(url);
        };
        const saveBtn = createButton("保存配置", "#ec4899", "#be185d");
        saveBtn.style.marginTop = "1rem";
        saveBtn.onclick = () => {
            const inputs = panel.querySelectorAll("input");
            inputs.forEach(input => {
                config[input.dataset.type][input.dataset.index] = input.value;
            });
            saveConfig();
            alert("配置已保存,请刷新页面生效");
            overlay.remove();
        };
        const resetBtn = createButton("重置默认", "#f43f5e", "#e11d48");
        resetBtn.style.marginTop = "0.5rem";
        resetBtn.onclick = () => {
            if (confirm("确定要重置所有配置为默认值吗?")) {
                Object.keys(defaultConfig).forEach(key => {
                    config[key] = [...defaultConfig[key]];
                });
                saveConfig();
                overlay.remove();
                alert("配置已重置,请刷新页面生效");
            }
        };
        const closeBtn = document.createElement("button");
        closeBtn.innerHTML = "&times;";
        closeBtn.style = `
            position: absolute;
            top: 1rem;
            right: 1rem;
            background: none;
            border: none;
            color: #64748b;
            font-size: 1.5rem;
            cursor: pointer;
            transition: color 0.2s;
        `;
        closeBtn.addEventListener('click', () => overlay.remove());
        closeBtn.addEventListener('mouseover', () => closeBtn.style.color = '#f43f5e');
        closeBtn.addEventListener('mouseout', () => closeBtn.style.color = '#64748b');
        panel.appendChild(title);
        panel.appendChild(createInputGroup("sans_namespace", "无衬线 浏览器命名空间"));
        panel.appendChild(createInputGroup("sans_latin", "无衬线 拉丁文"));
        panel.appendChild(createInputGroup("sans_simplified", "无衬线 简化字形"));
        panel.appendChild(createInputGroup("sans_traditional", "无衬线 传统字形"));
        panel.appendChild(createInputGroup("serif_namespace", "衬线 浏览器命名空间"));
        panel.appendChild(createInputGroup("serif_simplified", "衬线 简化字形"));
        panel.appendChild(createInputGroup("serif_traditional", "衬线 传统字形"));
        panel.appendChild(createInputGroup("mono_namespace", "等宽字体 浏览器命名空间"));
        panel.appendChild(createInputGroup("mono", "等宽字体"));
        buttonContainer.appendChild(importBtn);
        buttonContainer.appendChild(exportBtn);
        importExportSection.appendChild(buttonContainer);
        panel.appendChild(importExportSection);
        panel.appendChild(saveBtn);
        panel.appendChild(resetBtn);
        panel.appendChild(closeBtn);
        overlay.appendChild(panel);
        document.body.appendChild(overlay);
    }
    function generateCSS() {
        const [sans_namespace_1, sans_namespace_2, sans_namespace_3] = config.sans_namespace;
        const [sans_latin_1, sans_latin_2, sans_latin_3] = config.sans_latin;
        const [sans_simplified_1, sans_simplified_2, sans_simplified_3] = config.sans_simplified;
        const [sans_traditional_1, sans_traditional_2, sans_traditional_3] = config.sans_traditional;
        const [serif_namespace_1, serif_namespace_2, serif_namespace_3] = config.serif_namespace;
        const [serif_simplified_1, serif_simplified_2, serif_simplified_3] = config.serif_simplified;
        const [serif_traditional_1, serif_traditional_2, serif_traditional_3] = config.serif_traditional;
        const [mono_namespace_1, mono_namespace_2, mono_namespace_3] = config.mono_namespace;
        const [mono_1, mono_2, mono_3] = config.mono;
        return `
            /* 浏览器命名空间 */
            @font-face{font-family:sans-serif;src:local(${sans_namespace_1}),local(${sans_namespace_2}),local(${sans_namespace_3});}
            @font-face{font-family:serif;src:local(${serif_namespace_1}),local(${serif_namespace_2}),local(${serif_namespace_3});}
            @font-face{font-family:monospace;src:local(${mono_namespace_1}),local(${mono_namespace_2}),local(${mono_namespace_3});}
            /* 无衬线字体 拉丁文 */
            @font-face{font-family:"Arial";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Cambria";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Calibri";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Verdana";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Helvetica";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Helvetica Neue";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"HelveticaNeue";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"San Francisco";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"San Francisco Pro";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Segoe UI";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Google Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Google Sans Text";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Roboto";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Noto Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Lucida Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Lucida Grande";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"DejaVu Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Liberation Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            @font-face{font-family:"Open Sans";src:local(${sans_latin_1}),local(${sans_latin_2}),local(${sans_latin_3});}
            /* 无衬线字体 简化字形 */
            @font-face{font-family:"HarmonyOS Sans";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"Noto Sans SC";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"SimHei";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"黑体";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"Microsoft YaHei";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"微软雅黑";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"Microsoft YaHei UI";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"微软雅黑 UI";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"PingFang SC";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"Hiragino Sans GB";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            @font-face{font-family:"STHeiti";src:local(${sans_simplified_1}),local(${sans_simplified_2}),local(${sans_simplified_3});}
            /* 无衬线字体 传统字形 */
            @font-face{font-family:"Noto Sans TC";src:local(${sans_traditional_1}),local(${sans_traditional_2}),local(${sans_traditional_3});}
            @font-face{font-family:"Microsoft JhengHei";src:local(${sans_traditional_1}),local(${sans_traditional_2}),local(${sans_traditional_3});}
            @font-face{font-family:"微軟正黑體";src:local(${sans_traditional_1}),local(${sans_traditional_2}),local(${sans_traditional_3});}
            @font-face{font-family:"Microsoft JhengHei UI";src:local(${sans_traditional_1}),local(${sans_traditional_2}),local(${sans_traditional_3});}
            @font-face{font-family:"MHei";src:local(${sans_traditional_1}),local(${sans_traditional_2}),local(${sans_traditional_3});}
            /* 衬线字体 简化字形 */
            @font-face{font-family:"SimSun";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"宋体";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"NSimSun";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"新宋体";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"FangSong";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"FangSong_GB2312";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"仿宋";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"STSong";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"STFangsong";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            @font-face{font-family:"STZhongsong";src:local(${serif_simplified_1}),local(${serif_simplified_2}),local(${serif_simplified_3});}
            /* 等宽字体(代码) */
            @font-face{font-family:"Menlo";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Monaco";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Consolas";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Courier";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Courier New";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Andale Mono";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Ubuntu Mono";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Fira Code";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Fira Mono";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"DejaVu Sans Mono";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Liberation Mono";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            @font-face{font-family:"Source Code Pro";src:local(${mono_1}),local(${mono_2}),local(${mono_3});}
            /* 字体渲染优化 */
            body{-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:grayscale;}
        `;
    }
    const config = loadConfig();
    GM_registerMenuCommand("配置面板", createConfigUI);
    GM_addStyle(generateCSS());
})();