浏览器扩展可以覆盖CSS媒体功能/查询吗?

问题描述 投票:0回答:1

Chrome / ium或Firefox浏览器扩展程序(也称为加载项/ WebExtensions)是否会以某种方式覆盖媒体查询的结果?

我的意思是,对于JS window.match​Media()来说,这很容易:只需注入一个覆盖该JS函数的内容脚本。

但是如果使用“真正的”CSS媒体查询(在css文件中),这实际上是不可能的,是吗?

我显然可以注入自己的CSS,但这不是我想要的:我只是想触发网站的CSS做一些不同的事情,即假设一个不同的媒体查询结果。

一些背景:如果你想知道为什么,我的用例将是覆盖Firefox 67中引入的新prefers-color-scheme CSS media feature。(它目前不适用于支持浏览器/ WebExtensions的任何其他浏览器。)


交叉张贴在Mozilla's Discourse instance

javascript css google-chrome-extension firefox-addon firefox-webextensions
1个回答
0
投票

Workaround

感谢所有其他人,他们指出了我正确的方向。基本上,没有简单的方法,但你可以:

  • 注入一个内容脚本并迭代document.styleSheets,其中已经加载了所有已解析的样式表。这是艰巨的任务。但是,这都是只读的,因此您无法直接修改它。
  • 然后,您需要将结果发送回后台脚本(因为内容脚本无法访问所需的API)并通过browser.tabs.insertCSS手动应用CSS。

至于第一个任务,这里是代码片段(一次以功能方式编写,一次只是结构化),在给定媒体查询的情况下返回所有CSS。 你例如可以调用getCssForMediaQueryFunc("(prefers-color-scheme: dark)")并获取所有应用于暗色方案的CSS。

/**
 * Return CSS from the website for a specific query string.
 *
 * (functional implementation)
 *
 * @private
 * @param {string} queryString
 * @returns {string}
 */
function getCssForMediaQueryFunc(queryString) {
    return Array.from(document.styleSheets).reduce((prev, styleSheet) => {
        /* workaround for crazy HTML spec throwing an SecurityError here,
         * see https://discourse.mozilla.org/t/accessing-some-fonts-css-style-sheet-via-stylesheet/38717?u=rugkx
         * and https://stackoverflow.com/questions/21642277/security-error-the-operation-is-insecure-in-firefox-document-stylesheets */
        try {
            styleSheet.cssRules; // eslint-disable-line no-unused-expressions
        } catch (e) {
            return prev;
        }

        return Array.from(styleSheet.cssRules).reduce((prev, cssRule) => {
            if (cssRule instanceof CSSMediaRule) {
                if (cssRule.conditionText === queryString) {
                    return Array.from(cssRule.cssRules).reduce((prev, subCssRule) => {
                        return prev + subCssRule.cssText;
                    }, prev);
                }
            }
            return prev;
        }, prev);
    }, "");
}

/**
 * Return CSS from the website for a specific query string.
 *
 * @private
 * @param {string} queryString
 * @returns {string}
 */
function getCssForMediaQuery(queryString) { // eslint-disable-line no-unused-vars
    let cssRules = "";
    for (const styleSheet of document.styleSheets) {
        /* workaround for crazy HTML spec throwing an SecurityError here,
         * see https://discourse.mozilla.org/t/accessing-some-fonts-css-style-sheet-via-stylesheet/38717?u=rugkx
         * and https://stackoverflow.com/questions/21642277/security-error-the-operation-is-insecure-in-firefox-document-stylesheets */
        try {
            styleSheet.cssRules; // eslint-disable-line no-unused-expressions
        } catch (e) {
            continue;
        }

        for (const cssRule of styleSheet.cssRules) {
            if (cssRule instanceof CSSMediaRule) {
                if (cssRule.conditionText === queryString) {
                    for (const subCssRule of cssRule.cssRules) {
                        cssRules = cssRules + subCssRule.cssText;
                    }
                }
            }
        }
    }
    return cssRules;
}
  • 如前所述,您还需要覆盖window.match​Media()以伪造可以使用JS进行检测的网站的结果。但是,这也是it's own non-trivial task,需要将此功能从内容脚本导出到网站。 (也是假装很难。)

Proof of concept

an add-on hereavailable on addons.mozilla.org (AMO),我已经将这整个事实作为一个或多或少的概念验证。 (我在这里使用了永久链接,但附加组件当然可以在将来更新。)

Future

显然,这不是一个好方法,所以I've created a new Bugzilla issue找到一个更好的解决方案,例如一个特殊的Firefox API。

© www.soinside.com 2019 - 2024. All rights reserved.