我写了一个谷歌浏览器扩展程序,弹出一个带有自动填充字段的对话框,它有自己的风格,但是有些网站我的CSS完全坏了,看起来不太好。
我知道使用iFrame隔离样式,但在Google Chrome扩展程序中,无法以这种方式隔离我的HTML和CSS。另一种方法是将我的所有东西包装成一个单独的div,它有自己的id和相关的id,我这样做,但似乎它不适用于某些网站上有“硬”标签样式重载或“! CSS代码中的重要“指令。
所以,我想知道有没有办法真正以z方便的方式隔离我的样式,或者是我的坏carma重载每个小的CSS属性来修复每个站点的一个或另一个样式问题?
顺便说一句:我设置我的清单来加载“document_end”中的所有内容,但我发现它并没有应用于每次DOM准备就绪时每次加载的样式表。
答案 0 :(得分:21)
在提出问题时,您唯一的选择是使用iframe或具有非常高specificity的样式表,并明确设置可能影响样式的所有属性。最后一种方法非常麻烦,因为总有一些属性被你忽略了。因此,唯一可用于隔离样式表的方法是使用iframe。
此问题的解决方案 - 没有iframe的样式的隔离 - 是Shadow DOM(since Chrome 25)。您可以在HTML5 Rocks找到教程。对于使用Shadow DOM隔离样式的真实Chrome扩展程序,请参阅Display #Anchors(source code here)。
答案 1 :(得分:10)
由于我最近经历了这个问题的挑战,我想分享一些我认为有价值的信息。
首先,Rob W的回答是正确的。 Shadow DOM是解决此问题的正确方法。但是,在我的情况下,我不仅需要CSS隔离,还需要JavaScript事件。例如,如果用户单击位于隔离HTML中的按钮会发生什么?只有Shadow DOM才会变得非常丑陋,但我们还有另一个Web组件技术,即自定义元素。除了撰写本文时,Chrome中存在一个错误,它会阻止Chrome扩展中的自定义元素。请参阅我的问题here和here以及the bug here。
那么我们离开了哪里?我相信今天最好的解决方案是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>
接下来,在内容脚本中,在javascript中创建一个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扩展示例和许多不同信息的链接:https://anderspitman.net/blog/chrome-extension-content-script-stylesheet-isolation/
如果我的博客发生故障,这里是原帖的来源:
答案 2 :(得分:6)
all
.some-selector {
all: initial;
}
.some-selector * {
all: unset;
}
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;
}
答案 3 :(得分: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.
});
#yourDialogID中的元素不会受现有网页的影响。 find()函数返回一个常规的jQuery DOM元素,这样你就可以用它做任何你想做的事。
希望这会有所帮助。如果您有任何疑问,请与我们联系。
答案 4 :(得分:2)
使用iframe。这是一种解决方法,但工作正常。
Maxime写了article on it。