Могут ли расширения браузера перезаписывать медиа-функции / запросы CSS? - PullRequest
0 голосов
/ 24 апреля 2019

Могут ли расширения браузера Chrome / ium или Firefox (также называемые надстройками / WebExtensions) как-то перезаписать результат медиазапроса?

Я имею в виду, что для JS window.match​Media() это, вероятно, просто: просто вставьте скрипт содержимого, который перезаписывает эту функцию JS.

Но если используются «настоящие» медиа-запросы CSS (внутри CSS-файлов), это не реально, не так ли?

Я, очевидно, мог бы внедрить свой собственный CSS, но это не то, что я хочу: я просто хочу, чтобы CSS веб-сайта делал что-то другое, то есть предполагал, что другой результат медиа-запроса.

Некоторые предыстории: Если вам интересно, почему, мой вариант использования будет перезаписать новую prefers-color-scheme CSS-функцию , представленную в Firefox 67. (В настоящее время она недоступна для любых других браузеров, которые поддерживают браузер / WebExtensions.)


Перекрестная публикация на Экземпляр Дискурса Mozilla .

1 Ответ

0 голосов
/ 29 апреля 2019

Обход

Спасибо за всех, кто указал мне правильное направление. В принципе, нет простого пути, но вы можете:

  • внедрить скрипт содержимого и выполнить итерацию document.styleSheets, где все проанализированные таблицы стилей уже загружены. Это сложная задача. Однако все это доступно только для чтения, поэтому вы не можете изменить его напрямую.
  • Затем вам нужно отправить этот результат обратно в фоновый скрипт (поскольку у скриптов контента нет доступа к требуемому API) и применить CSS вручную через browser.tabs.insertCSS.

Что касается первой задачи, то здесь приведен фрагмент кода (один раз написан функциональным образом, а один раз просто структурный), который возвращает весь 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 для обнаружения. Тем не менее, это также это собственная нетривиальная задача и требует экспорта этой функции из скрипта контента на сайт. (Тоже подделка.)

Подтверждение концепции

Я реализовал все это в качестве более или менее проверенного концепта в дополнении здесь , также , доступном на addons.mozilla.org (AMO), (Я использовал постоянные ссылки здесь, но надстройка, конечно, может быть обновлена ​​в будущем.)

Future

Очевидно, что это не очень хороший метод, поэтому Я создал новую проблему Bugzilla , чтобы найти лучшее решение для этого, например. специальный Firefox API.

...