Reputation: 2399
I am writing a Chrome Extension where a small panel appears on top of the existing website. When I go to certain websites, I notice that the CSS of my panel has been over-written by the website's CSS. I am currently using Eric Meyer's CSS Reset but it does not seem to be doing the trick. Is there something else I can do?
Upvotes: 10
Views: 4785
Reputation: 2974
Like other answers, I got it working injecting the styles by myself. But today (v3), I had to do it like this:
manifest.json
{
...
"content_scripts": [
{
"js": ["main.js"],
"matches": [...]
}
],
"web_accessible_resources": [{
"resources": ["overrided-styles.css"],
"matches": [...]
}]
}
main.js
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css');
link.setAttribute('href', chrome.runtime.getURL('overrided-styles.css'));
document.querySelector('head').appendChild(link);
Upvotes: 0
Reputation: 466
An extension that I just wrote ran into similar problems. I've made most of them disappear, but not all of them. I think that I know why, but I haven't gotten around to fixing the exceptions (this is just a school assignment as of now).
Here is what I found: when a stylesheet is injected through the extension manifest or by the background page, it is treated as a user stylesheet, giving it cascade priority over the default browser stylesheet only. Adding !important
directives to your rules will not help, at least in my experience. User stylesheets (added by an extension or manually) can contain !important
directives, but they are not honoured by Chrome for some reason -- just check how they show up in the Chrome DevTools, without !important
. Adding id
attributes won't help either, as specificity will only trump where priority is equal otherwise.
What does work for me:
var ninjaCSS = document.createElement("link");
ninjaCSS.setAttribute("rel", "stylesheet");
ninjaCSS.setAttribute("type", "text/css");
ninjaCSS.setAttribute("href", chrome.extension.getURL('ninja.css'));
document.getElementById("head").appendChild(ninjaCSS);
This code is included in a JavaScript file that is listed in the manifest as a content script, and should run at document load. The CSS file is not listed in the manifest, but is included in the extension folder. Now the stylesheet is on an equal footing with the the other author stylesheets.
Of course, that is just the beginning. You can now give all elements in your panel an id
attribute (you probably already have). Whether you use a style reset or not is up to you. But you will have to make sure that your styles specify every single rule that a stylesheet in the wild might try to manipulate. If you do not plan to change a rule from its default, you must still specify that default value. Even if the default value is "none";
Finally, you must bravely ignore all warnings that the !important
directive is best used sparingly. Quite the opposite applies here. When you add !important
to every one of your style rules, it will be as if you had not used it at all as far as your panel's cascade is concerned. On the other hand, you will now be the boss of your panel. Trust me, somebody is going to tack an !important
directive on, say, their button:hover background-image
rule. Leading your well-crafted buttons to inexplicably morph into concert images of a 1985 bon jovi concert -- but only when the mouse is hovering, so no worries, right?
Upvotes: 1
Reputation: 25377
Here's a nifty 'hack' with iframes, where you don't actually instantiate an iframe:
It looks like this:
var iframe = document.createElement('iframe');
document.documentElement.appendChild(iframe); //fastest way to append to DOM: http://jsperf.com/insertbefore-vs-appendchild/2
iframe.contentDocument.body.innerHTML = '<a href="yomama.com">Normal link!!</a>';
Upvotes: 10
Reputation: 1
appendChild
solutions works for me (Devin G Rhode and jCyCle answers). But I noticed these solutions just add the attribute xmlns="http://www.w3.org/1999/xhtml"
. So I tested my code just by adding this xmlns attribute to my link tag (directly, not using JS) and it works too, don't know why.
Failing:
<link rel="stylesheet" type="text/css" href="filesystem:chrome-extension://................/temporary/Content/Styles/style.css" />
Working:
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" type="text/css" href="filesystem:chrome-extension://.............../temporary/Content/Styles/style.css" />
Upvotes: 0
Reputation: 16120
I'm not familiar with Chrome extensions themselves. But you could try scoping your panel within an 'id':
<div id='my-panel'>
PANEL GOES HERE
</div>
And then in the CSS just have #my-panel
as the first selector for all of your css. Take the reset css and add the #my-panel
identifier to each element defined there too. Might be tedious... but would ensure you're resetting all of your elements, and virtually guarantee that they'll be reset at a higher priority than anything the website might be defining.
Upvotes: 1