2011-02-11 76 views
5

我正在編寫一個谷歌瀏覽器擴展程序,在每個頁面上運行內容腳本。在我的內容腳本中,我將<div><ul><li>兒童注入頁面。我在樣式表中爲這些元素指定了一些樣式。如何不繼承鉻擴展內容腳本中的樣式

但我發現在一些隨機頁面上,我的元素將繼承網頁中定義的樣式,因爲我沒有爲div指定每個樣式屬性。

什麼是阻止我的注入元素繼承這些樣式的最佳方式?

在我看來,我既可以:

  • 在我的樣式表中指定的每一個風格,或
  • 我可以把(例如,通過看什麼計算的風格是在沒有干擾。)我的<div>在之內。不過,我必須在我的內容腳本的iframe和源頁面之間傳遞hella消息,因爲我的iframe src的chrome:// url和源頁面的url將被視爲跨源。
+1

技術上,有一個第三路線:[陰影DOM](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)。但是我不知道Chrome擴展的完整工作示例。有使用它的[display-anchors](https://github.com/Rob--W/display-anchors)擴展,但它不是與擴展通信的GUI。 – Xan 2014-06-23 12:57:09

+0

如何在頁面中加載css文件的順序。它是否像首頁的CSS加載,然後內容腳本的CSS文件?或相反亦然? – 2017-02-21 10:18:21

+0

現在答案已經過時了,你可以在css中使用`all:initial;` – 2017-10-16 00:02:41

回答

1

我會與第一選擇 - 完全指定您使用的元素的風格。但是這比我想象的要多一點。

首先,您必須完全指定容器元素。然後,對於它的後代,你不得不說他們也應該使用默認值或從父代繼承(直到容器)。最後,你必須指定每個其他元素的外觀,以便它們不是全部的普通跨度。

相關的API是getComputedStyleCSSStyleSheet接口從DOM Level 2 Style。您可以使用除widthheight之外的所有值,默認情況下應爲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

我最近創建了Boundary,一個CSS + JS庫來解決這樣的問題。邊界創建與現有網頁的CSS完全分離的元素。

以創建一個對話框爲例。安裝分界後,您可以在您的內容腳本中#yourDialogID

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. 
}); 

元素不會被現有的網頁受到影響做到這一點。

希望這會有所幫助。如果您有任何問題,請告訴我。

https://github.com/liviavinci/Boundary