簡體   English   中英

瀏覽器擴展可以覆蓋 CSS 媒體功能/查詢嗎?

[英]Can browser extensions overwrite CSS media features/query?

Chrome/ium 或 Firefox 瀏覽器擴展(也稱為附加組件/WebExtensions)是否真的可以以某種方式覆蓋媒體查詢的結果?

我的意思是,對於 JS window.matchMedia()這可能很簡單:只需注入一個覆蓋該 JS 函數的內容腳本。

但是如果使用“真正的”CSS 媒體查詢(在 css 文件中),這真的不可能,不是嗎?

我顯然可以注入自己的 CSS,但這不是我想要的:我只想觸發網站的 CSS 做一些不同的事情,即假設不同的媒體查詢結果。

一些背景:如果你想知道為什么,我的用例是覆蓋 Firefox 67 中引入的新prefers-color-scheme CSS 媒體功能。(它目前不適用於支持瀏覽器/WebExtensions 的任何其他瀏覽器。)


Mozilla 的 Discourse 實例上交叉發布。

解決方法

感謝所有其他人,他們為我指明了正確的方向。 基本上,沒有簡單的方法,但您可以:

  • 注入內容腳本並迭代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.matchMedia()以偽造可以使用 JS 進行檢測的網站的結果。 然而,這也是它自己的重要任務,需要將此功能從內容腳本導出到網站。 (也很難偽裝。)

概念驗證

在此處的附加組件中將這整件事實現為或多或少的概念驗證,也可在 addons.mozilla.org (AMO) 上獲得 (我在這里使用了永久鏈接,但將來當然可能會更新附加組件。)

未來

顯然,這不是一個好方法,所以我創建了一個新的 Bugzilla 問題來找到更好的解決方案,例如一個特殊的 Firefox API。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM