【问题标题】:Can browser extensions overwrite CSS media features/query?浏览器扩展可以覆盖 CSS 媒体功能/查询吗?
【发布时间】:2019-04-24 20:39:12
【问题描述】:

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上交叉发布。

【问题讨论】:

  • 所有 CSS 都被加载到 document.stylesheets 中,JavaScript 可以读取和修改它,就像它可以修改 DOM 的其余部分一样。如果扩展程序无法进入它,我会感到惊讶。
  • 谢谢,虽然很快调查了一下,但这似乎很难:那里没有纯 CSS,有 CSS 列表和远程位置。最后,看起来我需要重新下载文件,甚至在我的插件中编写自己的 CSS 解析器才能做到这一点。
  • styleSheet 对象包含已解析的样式,类似于 DOM 包含已解析的 HTML 的方式。可以直接遍历修改属性,不需要自己去解析文件。
  • @Barmar 好的,如果您愿意,请随时提交真实答案(附上一些细节)。在 cmets 中讨论这个是没有意义的。
  • 我不会详细说明您要执行的操作,但这里有一个动态修改样式表的代码示例:stackoverflow.com/a/8630641/1491895

标签: javascript css google-chrome-extension firefox-addon firefox-addon-webextensions


【解决方案1】:

解决方法

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

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

至于第一个任务,这里是代码 sn-p(一次以函数方式编写,一次以结构方式编写)返回所有 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;
}

(最新代码should be accessible here

  • 如前所述,您还需要覆盖window.match​Media() 来伪造可以使用JS 进行检测的网站的结果。但是,这也是it's own non-trivial task,需要将此功能从内容脚本导出到网站。 (也很难伪装。)

概念证明

我在an add-on hereavailable on addons.mozilla.org (AMO) 中或多或少地将整个事情实现为概念验证。 (我在这里使用了永久链接,但该插件当然可能会在将来更新。)

未来

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 2013-08-26
    • 2013-04-24
    • 2016-02-25
    • 1970-01-01
    • 2017-02-17
    • 2012-05-29
    相关资源
    最近更新 更多