Greasy Fork is available in English.
强制缩放 + 自动修复滚动容器(兼容所有主流网站)Force zoom + auto-fix scroll containers (Compatible with all major websites)
// ==UserScript==
// @name Force two-finger zoom on mobile web pages 强制手机网页双指缩放
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 强制缩放 + 自动修复滚动容器(兼容所有主流网站)Force zoom + auto-fix scroll containers (Compatible with all major websites)
// @author Manning9264
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAABd0lEQVR4nO2WX0oCURjFfyj6kvVqtIRsD9UGsiKsHURmZS0iwmX0x9aTRZYptIBeIh/yReODM3ARyubeaSTwwIUZ5p5zvrnfN4eBGf4x8kAFaAJPQF/Lrm/0zPb8CbaBHjCasLrAVpLGGaDhGNwBx8AyMKdVAk6AlrPvQtxgNCT4CexPELVnB9obFRF87CMJrsbgrTlFbPqa552e25vHRVXcFyDnU0DF6blPL7PAvTR2fAq4FfkIf9Slce1DfhbZpt0XJWlYTsTGh8iFgALmpWFasdFPoIAFabz7kHsJtGAlpAVNkS3hfHEmjUsf8p7IrYDP8CHkM8wBrxKweI2Lmrgd3yAylJ0otnj9LdaBATAENgjAIvDmFFHV0X6HrN58IM55qHlbQlERI8VrXSFT0LJpP3V6PpR5Jgnztu7Lzkz8tDpJHHt7zDyCDdOufr+6CitLuUfgStPuPXCGonOMFh5LpIjizJwpmLuJNT5wqeJwmuYzkDa+AO0YhpRFIZffAAAAAElFTkSuQmCC
// @match *://*/*
// @grant none
// @run-at document-start
// @license MIT
// @supportURL https://github.com/Hurricane-0121/Force-mobile-zoom/issues
// ==/UserScript==
(function() {
'use strict';
const FORCED_MAX_SCALE = '10.0';
const FORCED_USER_SCALABLE = 'yes';
// ---------- 修正 viewport meta ----------
function fixViewportMeta(metaNode) {
if (!metaNode || metaNode.name !== 'viewport') return;
let content = metaNode.getAttribute('content') || '';
if (!content.trim()) {
metaNode.setAttribute('content', `width=device-width, initial-scale=1.0, maximum-scale=${FORCED_MAX_SCALE}, user-scalable=${FORCED_USER_SCALABLE}`);
return;
}
let parts = content.split(',').map(part => part.trim()).filter(part => part.length > 0);
let newParts = [];
let foundUserScalable = false,
foundMaxScale = false,
foundWidth = false;
for (let part of parts) {
let eqIndex = part.indexOf('=');
if (eqIndex > 0) {
let key = part.substring(0, eqIndex).trim().toLowerCase();
if (key === 'user-scalable') {
newParts.push(`user-scalable=${FORCED_USER_SCALABLE}`);
foundUserScalable = true;
} else if (key === 'maximum-scale') {
newParts.push(`maximum-scale=${FORCED_MAX_SCALE}`);
foundMaxScale = true;
} else if (key === 'width') {
newParts.push(part);
foundWidth = true;
} else {
newParts.push(part);
}
} else {
newParts.push(part);
}
}
if (!foundUserScalable) newParts.push(`user-scalable=${FORCED_USER_SCALABLE}`);
if (!foundMaxScale) newParts.push(`maximum-scale=${FORCED_MAX_SCALE}`);
if (!foundWidth) newParts.push(`width=device-width`);
metaNode.setAttribute('content', newParts.join(', '));
}
function ensureViewportMeta() {
let metaList = document.querySelectorAll('meta[name="viewport"]');
if (metaList.length > 0) {
metaList.forEach(meta => fixViewportMeta(meta));
} else if (document.head) {
let newMeta = document.createElement('meta');
newMeta.name = 'viewport';
newMeta.setAttribute('content', `width=device-width, initial-scale=1.0, maximum-scale=${FORCED_MAX_SCALE}, user-scalable=${FORCED_USER_SCALABLE}`);
document.head.appendChild(newMeta);
} else {
let headObserver = new MutationObserver(function(mutations, obs) {
if (document.head) {
obs.disconnect();
ensureViewportMeta();
}
});
headObserver.observe(document.documentElement, { childList: true, subtree: true });
}
}
// ---------- 暴力修复滚动:强制所有可能滚动的元素拥有正确的 overflow ----------
function forceScrollOnAllElements() {
let allElements = document.querySelectorAll('*');
allElements.forEach(el => {
if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE') return;
let scrollHeight = el.scrollHeight;
let clientHeight = el.clientHeight;
if (scrollHeight > clientHeight) {
el.style.setProperty('overflow-y', 'auto', 'important');
el.style.setProperty('-webkit-overflow-scrolling', 'touch', 'important');
el.style.setProperty('touch-action', 'manipulation', 'important');
}
});
}
// 定期扫描(应对动态内容)
function startPeriodicScan() {
setInterval(forceScrollOnAllElements, 2000);
}
// 观察 DOM 变化,增量修复
function observeDynamicContent() {
if (!document.body) {
setTimeout(observeDynamicContent, 100);
return;
}
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.addedNodes && mutation.addedNodes.length) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
let elements = node.querySelectorAll ? node.querySelectorAll('*') : [];
[node, ...elements].forEach(el => {
if (el.scrollHeight > el.clientHeight) {
el.style.setProperty('overflow-y', 'auto', 'important');
el.style.setProperty('-webkit-overflow-scrolling', 'touch', 'important');
el.style.setProperty('touch-action', 'manipulation', 'important');
}
});
}
});
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
// 启动所有修复
function init() {
if (document.head) {
ensureViewportMeta();
} else {
let headReadyObserver = new MutationObserver(function(mutations, obs) {
if (document.head) {
obs.disconnect();
ensureViewportMeta();
}
});
headReadyObserver.observe(document.documentElement, { childList: true, subtree: true });
}
if (document.body) {
forceScrollOnAllElements();
startPeriodicScan();
observeDynamicContent();
} else {
document.addEventListener('DOMContentLoaded', () => {
forceScrollOnAllElements();
startPeriodicScan();
observeDynamicContent();
});
}
window.addEventListener('load', forceScrollOnAllElements);
}
init();
})();