// ==UserScript== // @name TextClarity 清晰文本助手 Pro // @namespace 灵感来源于https://github.com/syhyz1990/mactype // @version 2.0.0 // @description 浏览器文字渲染深度优化,支持四种增强模式,特别优化 Edge/Chrome 显示效果 // @author imiaox // @license MIT // @match *://*/* // @run-at document-start // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // ==/UserScript== (function () { 'use strict'; // ─── 常量 ─────────────────────────────────────────── const VERSION = '2.0.0'; const STORE_KEY = 'tc_pro_config'; const STYLE_ID = 'tc-pro-text-styles'; const PANEL_STYLE_ID = 'tc-pro-panel-styles'; const PANEL_ID = 'tc-pro-panel'; const MODES = { shadow: { label: '阴影增强', desc: '通过微偏移阴影提升文字边缘锐度,兼容性最好,推荐日常使用' }, stroke: { label: '描边增强', desc: '通过细描边模拟字重增加,适合纤细字体或小字号场景' }, combined: { label: '混合增强', desc: '阴影 + 描边同时作用,效果最强,适合高分屏或追求极致清晰' }, weight: { label: '字重提升', desc: '直接增加 font-weight,最自然但可能影响布局' } }; const DEFAULTS = { mode: 'shadow', intensity: 0.35, weightBoost: 80, letterSpacing: 0, smoothing: true, enableKerning: true, whitelist: [] }; // ─── 主类 ──────────────────────────────────────────── class TextClarity { constructor() { this.cfg = this._load(); this._rafId = 0; this._panelOpen = false; this._init(); } // ── 配置 ── _load() { const raw = GM_getValue(STORE_KEY, null); return raw ? { ...DEFAULTS, ...raw, whitelist: raw.whitelist || [] } : { ...DEFAULTS }; } _save() { GM_setValue(STORE_KEY, this.cfg); } _isEnabled() { return !this.cfg.whitelist.includes(location.host); } // ── 初始化 ── _init() { // 尽早注入样式 if (this._isEnabled()) { this._injectTextCSS(); } this._startObserver(); this._registerMenu(); } // ── CSS 生成引擎 ── _buildCSS() { const { mode, intensity, weightBoost, letterSpacing, smoothing, enableKerning } = this.cfg; const i = intensity; // 根据模式生成核心效果 let effectCSS = ''; switch (mode) { case 'shadow': // 两层微阴影:外层提锐度,内层稳定边缘 effectCSS = ` text-shadow: 0 0 ${this._p(0.4 + i * 1.2)} currentColor, 0 0 ${this._p(i * 0.3)} currentColor;`; break; case 'stroke': effectCSS = ` -webkit-text-stroke: ${this._p(0.08 + i * 0.45)} currentColor; paint-order: stroke fill;`; break; case 'combined': effectCSS = ` -webkit-text-stroke: ${this._p(0.05 + i * 0.2)} currentColor; paint-order: stroke fill; text-shadow: 0 0 ${this._p(0.3 + i * 0.6)} currentColor;`; break; case 'weight': // 纯字重模式不使用文本特效 break; } // 字重加粗 const weightCSS = weightBoost > 0 ? `font-weight: ${400 + weightBoost} !important;` : ''; // 字间距 const spacingCSS = letterSpacing > 0 ? `letter-spacing: ${letterSpacing}em;` : ''; // 抗锯齿策略 const smoothingCSS = smoothing ? `-webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;` : `-webkit-font-smoothing: subpixel-antialiased;`; // OpenType 排版特性 const featureCSS = enableKerning ? `font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 1; font-variant-ligatures: common-ligatures contextual; font-kerning: normal;` : ''; return `/* TextClarity Pro v${VERSION} */ *:not(pre):not(code):not(kbd):not(samp):not(var):not(math):not(script):not(style):not(iframe):not(video):not(canvas):not(svg):not(img) { text-rendering: optimizeLegibility; font-synthesis: none; text-size-adjust: 100%; ${smoothingCSS} ${featureCSS} ${effectCSS} ${weightCSS} ${spacingCSS} } ::selection { background: rgba(51, 143, 255, 0.3) !important; } ::target-text { background: rgba(255, 213, 0, 0.35); }`; } _p(v) { // 精简到两位小数,去除尾零 return `${Math.round(v * 100) / 100}px`; } // ── 样式注入(复用