Как не наследовать стили в скрипте содержимого расширения Chrome - PullRequest
5 голосов
/ 11 февраля 2011

Я пишу расширение Google Chrome, которое запускает скрипт контента на каждой странице. В моем скрипте контента я вставляю <div> с некоторыми <ul> и <li> дочерними элементами на страницу. Я указываю несколько стилей для этих элементов в таблице стилей.

Но я обнаружил, что на некоторых случайных страницах мои элементы будут наследовать стили от тех, которые определены на веб-странице, поскольку я не указал каждое отдельное свойство стиля для своих элементов div.

Как лучше всего помешать моим внедренным элементам наследовать эти стили?

Мне кажется, я мог бы:

  • указать каждый отдельный стиль в моей таблице стилей (например, посмотрев, что такое вычисленные стили, когда нет помех), или
  • Я мог бы положить <div> внутрь <iframe>. Однако затем мне придется выполнить передачу сообщений hella между iframe моего скрипта содержимого и исходной страницей, поскольку URL chrome:// моего iframe src и URL-адреса http:// исходных страниц будут считаться перекрестными. *

Ответы [ 2 ]

1 голос
/ 12 февраля 2011

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

Во-первых, вы должны полностью указать элемент контейнера. Затем для его потомков вы должны сказать, что они также должны использовать значения по умолчанию или наследовать от своего родителя (вплоть до контейнера). Наконец, вы должны указать внешний вид всех остальных элементов, чтобы они не были простыми.

Соответствующими API являются getComputedStyle и CSSStyleSheet интерфейс от DOM Level 2 Style . Вы можете использовать все значения, кроме width и height, которые по умолчанию должны быть auto. Вам также необходимо загрузить таблицу стилей по умолчанию, такую ​​как таблица стилей агента пользователя Webkit . Затем вы можете вызвать следующую функцию, чтобы создать полную таблицу стилей, которую можно вставить в документ.

Обратите внимание, что когда вы вставляете таблицу стилей в целевой документ, вам нужно будет сделать селектор контейнера как можно более конкретным, поскольку веб-страница может дать правила, которые имеют специфичность , чем ваши правила. Например, в <html id=a><head id=b><style>#a #b * {weird overrides}</style></head>, #a #b * имеет более высокую специфичность, чем #yourId div. Но я думаю, что это необычно.

Примечание. По какой-то причине Chrome выдает ошибку «Не удалось загрузить ресурс» при загрузке CSS, если только он не находится в <link> текущего документа. Поэтому вы должны включить html.css на страницу, которая также вызывает эту функцию.

// CSS 2.1 inherited prpoerties
var inheritedProperties = [
    'azimuth', 'border-collapse', 'border-spacing', 'caption-side',
    'color', 'cursor', 'direction', 'elevation', 'empty-cells',
    'font-family', 'font-size', 'font-style', 'font-variant',
    'font-weight', 'font', 'letter-spacing', 'line-height',
    'list-style-image', 'list-style-position', 'list-style-type',
    'list-style', 'orphans', 'pitch-range', 'pitch', 'quotes',
    'richness', 'speak-header', 'speak-numeral', 'speak-punctuation',
    'speak', 'speech-rate', 'stress', 'text-align', 'text-indent',
    'text-transform', 'visibility', 'voice-family', 'volume',
    'white-space', 'widows', 'word-spacing'];
// CSS Text Level 3 properties that inherit http://www.w3.org/TR/css3-text/
inheritedProperties.push(
    'hanging-punctuation', 'line-break', 'punctuation-trim',
    'text-align-last', 'text-autospace', 'text-decoration-skip',
    'text-emphasis', 'text-emphasis-color', 'text-emphasis-position',
    'text-emphasis-style', 'text-justify', 'text-outline',
    'text-shadow', 'text-underline-position', 'text-wrap',
    'white-space-collapsing', 'word-break', 'word-wrap');
/**
 * Example usage:
       var fullStylesheet = completeStylesheet('#container', 'html.css').map(
           function(ruleInfo) {
               return ruleInfo.selectorText + ' {' + ruleInfo.cssText + '}';
           }).join('\n');
 * @param {string} containerSelector The most specific selector you can think
 *     of for the container element; e.g. #container. It had better be more
 *     specific than any other selector that might affect the elements inside.
 * @param {string=} defaultStylesheetLocation If specified, the location of the
 *     default stylesheet. Note that this script must be able to access that
 *     locatoin under same-origin policy.
 * @return {Array.<{selectorText: string, cssText: string}>} rules
 */
var completeStylesheet = function(containerSelector,
                                  defaultStylesheetLocation) {
  var rules = [];
  var iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  document.body.appendChild(iframe);  // initializes contentDocument
  try {
    var span = iframe.contentDocument.createElement('span');
    iframe.contentDocument.body.appendChild(span);
    /** @type {CSSStyleDeclaration} */
    var basicStyle = iframe.contentDocument.defaultView.getComputedStyle(span);
    var allPropertyValues = {};
    Array.prototype.forEach.call(basicStyle, function(property) {
      allPropertyValues[property] = basicStyle[property];
    });
    // Properties whose used value differs from computed value, and that
    // don't have a default value of 0, should stay at 'auto'.
    allPropertyValues['width'] = allPropertyValues['height'] = 'auto';
    var declarations = [];
    for (var property in allPropertyValues) {
      var declaration = property + ': ' + allPropertyValues[property] + ';';
      declarations.push(declaration);
    }
    // Initial values of all properties for the container element and
    // its descendants
    rules.push({selectorText: containerSelector + ', ' +
                              containerSelector + ' *',
                cssText: declarations.join(' ')});

    // For descendants, some of the properties should inherit instead
    // (mostly dealing with text).
    rules.push({selectorText: containerSelector + ' *',
                cssText: inheritedProperties.map(
                    function(property) {
                      return property + ': inherit;'
                    }).join(' ')});

    if (defaultStylesheetLocation) {
      var link = iframe.contentDocument.createElement('link');
      link.rel = 'stylesheet';
      link.href = defaultStylesheetLocation;
      iframe.contentDocument.head.appendChild(link);
      /** @type {CSSStyleSheet} */
      var sheet = link.sheet;
      Array.prototype.forEach.call(
          sheet.cssRules,
          /** @param {CSSStyleRule} cssRule */
          function(cssRule) {
        rules.push({
            selectorText: containerSelector + ' ' + cssRule.selectorText,
            cssText: cssRule.style.cssText});
      });
    }
    return rules;
  } finally {
    document.body.removeChild(iframe);
  }
};
0 голосов
/ 17 октября 2014

Я недавно создал Boundary, библиотеку CSS + JS для решения таких проблем.Граница создает элементы, которые полностью отделены от CSS существующей веб-страницы.

Например, создайте диалоговое окно.После установки Boundary вы можете сделать это в своем скрипте содержимого

var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName");

Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");

Boundary.appendToBox(
    "#yourDialogID",
    "<button id='submit_button'>submit</button>"
);

Boundary.find("#submit_button").click(function() {
  // find() function returns a regular jQuery DOM element
  // so you can do whatever you want with it.
  // some js after button is clicked.
});

Элементы в #yourDialogID не будут затронуты существующей веб-страницей.

Надеюсь, это поможет.Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы.

https://github.com/liviavinci/Boundary

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...