如何真正隔离谷歌浏览器扩展中的样式表?

我写了谷歌浏览器扩展,popup对话框自动填充字段和它自己的风格,但也有一些网站,我的CSS变得完全破碎,看起来不是很好。

我知道使用iFrames隔离样式,但在Google Chrome扩展中,没有办法通过这种方式来隔离我的HTML和CSS。 另一种方法是将所有我的东西都包装在分离的div中,并使用它自己的ID和相应的ID作为样式,我这样做,但似乎在一些硬标签样式重载或“!important”指令的站点上不起作用CSS代码。

所以我想知道是否有一些方法可以用方便的方式真正地隔离我的样式,或者是我的坏的瑕疵是重载每个小CSS属性来修复每个网站上的一个或另一个样式错误?

顺便说一句:我build立我的清单加载所有东西在“document_end”,但我看到它不适用于任何DOM准备好之前每次加载的样式表。

在提出问题时,唯一的select是使用iframe或具有非常高特异性的样式表,并明确设置可能影响样式的所有属性。 最后一个方法非常麻烦,因为总会有一些被你忽略的属性。 因此,隔离样式表唯一可用的方法是使用iframe。

这个问题的解决scheme – 无iframe的样式分离 – 是Shadow DOM ( 自Chrome 25以来 )。 你可以在HTML5 Rocks上find一个教程。 对于使用Shadow DOM隔离样式的真实世界的Chrome扩展,请参阅显示#安装 ( 此处为源代码 )。

正如我最近经历了这个问题的诀窍,我想分享一些我认为有价值的信息。

首先,Rob W的答案是正确的。 Shadow DOM是解决这个问题的正确方法。 但是,在我的情况下,我不仅需要CSS隔离,还需要JavaScript事件。 例如,如果用户单击一个位于独立HTML内的button,会发生什么情况? 这只会影响DOM,但是我们有另一个Web Components技术,Custom Elements来解决这个问题。 除了截至撰写本文为止,chrome中都存在一个错误,它会阻止扩展中的自定义元素。 在这里和这里看到我的问题和错误在这里 。

那么,我们在哪里呢? 我相信今天最好的解决scheme是IFrames,这是我一起去的。 文章shahalpk链接是伟大的,但它只描述部分的过程。 以下是我如何做到的:

首先,为您的独立小部件创build一个html文件和js文件。 这些文件中的所有内容都将在iframe的隔离环境中运行。 一定要从html文件中获取你的js文件。

 //iframe.js var button = document.querySelector('.my-button'); button.addEventListener('click', function() { // do useful things }); //iframe.html <style> /* css */ </style> <button class='my-button'>Hi there</button> <script src='iframe.js'></script> 

接下来,在您的内容脚本中,在javascript中创build一个iframe元素。 您需要在JavaScript中执行此操作,因为您必须使用chrome.extension.getURL才能获取您的iframe html文件:

 var iframe = document.createElement('iframe'); iframe.src = chrome.extension.getURL("iframe.html"); document.body.appendChild(iframe); 

就是这样。

有一件事要记住:如果你需要在iframe和内容脚本的其余部分之间进行通信,你需要chrome.runtime.sendMessage()到后台页面,然后chrome.tabs.sendMessage从后台页面返回到标签。 他们不能直接沟通。

编辑:我写了一篇博客文章,详细介绍了我通过我的过程学到的一切,其中包括一个完整的Chrome扩展示例和大量不同信息的链接:

http://anderspitman.com/2014/08/04/chrome-extension-content-script-stylesheet-isolation/

要么all使用

 .some-selector { all: initial; } .some-selector * { all: unset; } 

或者使用Shadow DOM

图书馆

 function Widget(nodeName, appendTo){ this.outer = document.createElement(nodeName || 'DIV'); this.outer.className = 'extension-widget-' + chrome.runtime.id; this.inner = this.outer.createShadowRoot(); (appendTo || document.body).appendChild(this.outer); } Widget.prototype.show = function(){ this.outer.style.display = 'block'; return this; }; Widget.prototype.hide = function(){ this.outer.style.display = 'none'; return this; }; 

用法

 var myWidget = new Widget(); myWidget.inner.innerHTML = '<h1>myWidget</h1>'; 

您可以通过myWidget.inner和外部通过myWidget.outer访问小部件内容。

样式

 /* * Reset Widget Wrapper Element */ .extension-widget-__MSG_@@extension_id__ { background: none; border: none; bottom: auto; box-shadow: none; color: black; cursor: auto; display: inline; float: none; font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-size: inherit; font-style: normal; font-variant: normal; font-weight: normal; height: auto; left: auto; letter-spacing: 0; line-height: 100%; margin: 0; max-height: none; max-width: none; min-height: 0; min-width: 0; opacity: 1; padding: 0; position: static; right: auto; text-align: left; text-decoration: none; text-indent: 0; text-shadow: none; text-transform: none; top: auto; vertical-align: baseline; white-space: normal; width: auto; z-index: 2147483648; } /* * Add your own styles here * but always prefix them with: * * .extension-widget-__MSG_@@extension_id__ * */ .extension-widget-__MSG_@@extension_id__{ position: fixed; top: 100px; margin: 0 auto; left: 0; right: 0; width: 500px; } .extension-widget-__MSG_@@extension_id__::shadow h1 { display: block; margin: 0 auto; padding: 20px; background-color: yellow; border: 10px solid green; font-size: 20px; text-align: center; } 

使用iframe。 这是一个解决方法,但工作正常。

马克西姆已经写了一篇文章 。

我最近创build了Boundary,一个CSS + JS库来解决这个问题。 边界创build与现有网页的CSS完全分离的元素。

以创build一个对话框为例。 安装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() { // some js after button is clicked. }); 

#yourDialogID中的元素不会受到现有网页的影响。 find()函数返回一个常规的jQuery DOM元素,所以你可以随心所欲地做任何事情。

希望这可以帮助。 如果您有任何问题,请告诉我。

https://github.com/liviavinci/Boundary