2011-02-11 6 views
5

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

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

Каков наилучший способ, которым я могу остановить введённые элементы от наследования этих стилей?

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

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

Технически, есть третий путь: [Shadow DOM] (http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/). Но я не знаю полного рабочего примера для расширения Chrome. Существует расширение [display-anchors] (https://github.com/Rob--W/display-anchors), но оно не является графическим интерфейсом, который связывается с расширением. – Xan

+0

Каким образом порядок загрузки css-файлов на странице. это как загружается первая страница css, а затем файлы css для сценариев контента? или наоборот? –

+0

ответы устарели сейчас, вы можете использовать 'all: initial;' в css now –

ответ

1

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

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

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

Обратите внимание, что при вставке таблицы стилей в целевой документ вам нужно будет сделать селектор контейнера максимально конкретным, поскольку веб-страница, возможно, может давать правила, которые имеют более высокий specificity, чем ваши правила. Например, в <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

Отлично, спасибо за подробный ответ @yonran. Re: ошибка CSS Chrome, я включаю ссылку на таблицу стилей в расширении manifest.json: '" content_scripts ": [{" matches ": [" http: // */* "]," css ": [" my. css "]}]' и всякий раз, когда мне нужно ссылаться на локальный ресурс в моем сценарии содержимого, я получаю его через 'chrome.extension.getURL (« ... »);' – mark

+0

У меня возникла одна проблема с вышеперечисленным. Когда я пытаюсь 'iframe.contentDocument.defaultView.getComputedStyle (span)' проблема в том, что 'iframe.contentDocument.defaultView' не определен. – mark

+0

У меня проблемы, связанные с ошибкой Chrome http://code.google.com/p/chromium/issues/detail?id=49001. Проблема проявилась, когда я использовал протокол file: //. Я настроил локальный веб-сервер и смог получить доступ к желаемому свойству cssRules, используя протокол http: //. – mark

0

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

Возьмите создание диалога, например.После установки Границы, вы можете сделать это в вашем скрипте содержимого

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

+0

Пожалуйста, ** остановитесь и прочитайте мои комментарии ** на [ваш предыдущий ответ] (http://stackoverflow.com/a/26431160/934239). Если вы продолжите копировать этот ответ без каких-либо изменений, я должен буду его отмечать, несмотря на его полезность. – Xan

Смежные вопросы