SOURCE

console 命令行工具 X clear

                    
>
console
(() => {
    // 检测原生 style是否支持 scoped 
    if (document.createElement("STYLE").scoped !== undefined) {
        return;
    }
    document.createElement("STYLE").__proto__.scoped = false;

    /**
     * 为选择器添加范围前缀scope
     * @param {String} selector css选择器
     * @param {String} scope css范围前缀
     * @returns 返回修改后的css选择器
     */
    function updateSelector(selector, scope) {
        return selector.split(",").map(x => x.replace(/((?<=^\s*)\s|^)([\S])/, "$1" + scope + " $2")).join(",");
    }

    /**
     * 将css代码中所有选择器都加上范围前缀scope
     * @param {String} css css代码
     * @param {String} scope css范围前缀
     * @returns 返回修改后的css代码
     */
    function updateCss(css, scope) {
        // css = css.replace(/[\n\r\s]+/g, " "); // 去空格和回车
        css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + encodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 去字符串干扰 
        css = css.replace(/[^{}]+{/g, x => updateSelector(x, scope));
        css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + decodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 还原字符串 
        return css;
    }

    /**
     * 处理 <style> 标签
     * @param style dom
     */
    function updateStyle(style) {
        if (!style
            || style.parentElement == null
            || style.parentElement == document.head
            || style.parentElement == document.body
            || !style.hasAttribute("scoped")
            || style.scoped === true) {
            return;
        }
        style.scoped = true; // 防止重复处理

        const scope = ("_" + (Math.random() * 100000000).toString("36")).replace('.', '');
        style.parentElement.setAttribute(scope, '');

        style.textContent = updateCss(style.textContent, "[" + scope + "]");
    }

    // 当观察到变动时执行的回调函数
    const callback = function (mutationsList) {
        if (mutationsList.length == 0) {
            return;
        }
        for (const mutation of mutationsList) {
            for (const node of mutation.addedNodes) {
                if (node.nodeName === "STYLE") {
                    updateStyle(node);
                }
            }
        }
    };

    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback);
    const config = { childList: true, subtree: true };
    observer.observe(document, config);

    // MutationObserver 是异步的,回调时间不可控,所以需要设置一个轮询
    setInterval(() => callback(observer.takeRecords()), 100);

    [...document.getElementsByTagName('style')].forEach(x => updateStyle(x));

})();
<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<title>菜鸟教程(runoob.com)</title>
	<style type="text/css">
		h1 {
			color: green;
		}

		p {
			color: black;
		}
	</style>
</head>

<body>

	<div>
		<style type="text/css" scoped>
			h1 {
				color: red;
			}

			p {
				color: blue;
			}
		</style>
		<h1>这个标题是红色的</h1>
		<p>这个段落是蓝色的。</p>
	</div>

	<h1>这个标题是绿色的</h1>
	<p>这个段落是黑色的。</p>

</body>

</html>