如何在Google Chrome扩展程序中真正隔离样式表?

smi*_*art 28 css isolation google-chrome-extension

我写了一个谷歌浏览器扩展程序,弹出一个带有自动填充字段的对话框,它有自己的风格,但是有些网站我的CSS完全坏了,看起来不太好看.

我知道使用iFrames隔离样式,但在Google Chrome扩展程序中,无法以这种方式隔离我的HTML和CSS.另一种方法是将我的所有东西包装成一个单独的div,它有自己的id和相关的id,我这样做,但似乎它不适用于某些网站上有"硬"标签样式重载或"! CSS代码中的重要"指令.

所以,我想知道有没有办法真正以z方便的方式隔离我的样式,或者是我的坏carma重载每个小CSS属性来修复每个站点的一个或另一个样式问题?

顺便说一下:我设置我的清单来加载"document_end"中的所有内容,但我发现它并没有被应用到每次DOM准备就绪时每次加载的样式表.

Rob*_*b W 21

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

这个问题的解决方案 - 没有iframes的样式的分离 - 是Shadow DOM(自Chrome 25以来).你可以在HTML5 Rocks找到一个教程.对于使用Shadow DOM隔离样式的真实Chrome扩展程序,请参阅显示#Anchors(此处为源代码).


and*_*man 11

由于我最近经历了这个问题的挑战,我想分享一些我认为有价值的信息.

首先,Rob W的回答是正确的.Shadow DOM是解决此问题的正确方法.但是,在我的情况下,我不仅需要CSS隔离,还需要JavaScript事件.例如,如果用户单击位于隔离HTML中的按钮会发生什么?只有Shadow DOM才会变得非常丑陋,但我们还有另一个Web组件技术,即自定义元素.除了撰写本文时,Chrome中存在一个错误,它会阻止Chrome扩展中的自定义元素.见我的问题在这里,并在这里这里的bug.

那么我们离开了哪里呢?我相信今天最好的解决方案是IFrames,这就是我的选择.shahalpk链接的文章很棒,但它只描述了该过程的一部分.我是这样做的:

首先,为您的隔离小部件创建一个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> 
Run Code Online (Sandbox Code Playgroud)

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

var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);
Run Code Online (Sandbox Code Playgroud)

就是这样.

要记住一件事:如果您需要在iframe和内容脚本的其余部分之间进行通信,则需要将chrome.runtime.sendMessage()连接到后台页面,然后从后台页面返回chrome.tabs.sendMessage到选项卡.他们无法直接沟通.

编辑:我写了一篇博文,详细介绍了我通过我的过程学到的所有内容,包括一个完整的chrome扩展示例和许多不同信息的链接:

https://anderspitman.net/blog/chrome-extension-content-script-stylesheet-isolation/

如果我的博客发生故障,这里是原帖的来源:

博客文章

示例来源


HaN*_*riX 7

要么使用 all

.some-selector {
    all: initial;
}

.some-selector * {
    all: unset;
}
Run Code Online (Sandbox Code Playgroud)

或使用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;
};
Run Code Online (Sandbox Code Playgroud)

用法

var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';
Run Code Online (Sandbox Code Playgroud)

您可以通过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;
}
Run Code Online (Sandbox Code Playgroud)


Liv*_*ang 5

我最近创建了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() {
  // some js after button is clicked.
});
Run Code Online (Sandbox Code Playgroud)

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

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

https://github.com/liviavinci/Boundary


sha*_*lpk 2

使用 iframe。这是一个解决方法,但效果很好。

Maxime 写了一篇关于它的文章