26

My chrome extension needs to modify certain css rules on user's page. Accessing styles via document.styleSheets only gives access to styles linked from within the same domain. Other elements of document.styleSheets array have cssRules/rules set to null.

Why is it cross domain policy applies here? Styles are being applied anyway regardless of their origin, so what is the point? And how to get around it in my case?


EDIT:

The reason I need to MODIFY user css rules (as opposed to simply adding my own) is that I need to protect custom element injected by extension from being affected by * rules. see details in this question

Community
  • 1
  • 1
artemave
  • 6,786
  • 7
  • 47
  • 71
  • 2
    Would it help to do a complete CSS reset on all the elements you add?Perhaps this would help: http://stackoverflow.com/questions/4966030/how-not-to-inherit-styles-in-a-chrome-extension-content-script/4974909 – yonran Apr 15 '11 at 23:33
  • 1
    Yeah, I am kinda thinking in the same direction. – artemave Apr 16 '11 at 14:02
  • 2
    You could use the !important modifier to override other styles. – NoBugs Jun 25 '11 at 05:30
  • 1
    I have the same problem. When i iterate over the cssRules to modify some properties globally, i realized that the cssRules of external css are null, which has the most important rules – jscripter Mar 22 '14 at 07:21
  • Seems to be a security consideration. See the discussion here: https://bugs.chromium.org/p/chromium/issues/detail?id=143626#c11 – Rafael Emshoff Jan 20 '17 at 08:29

3 Answers3

6

Content scripts don't have any cross-domain privileges comparing to a regular javascript, so any limitations are carried over. See related question #1, question #2.

You can inject your own css style in the manifest:

"content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"]
    }
]

where you can try to overwrite original styles by defining rules with higher specificity.

You can also just tweak concrete element styles through javascript:

document.getElementById("id").style.property="value";
Community
  • 1
  • 1
serg
  • 109,619
  • 77
  • 317
  • 330
  • I've updated my question to indicate that defining my own css is not much of a help. – artemave Apr 15 '11 at 16:34
  • 1
    It appears to be impossible, even when adding an Access-Control-Allow-Origin header to the stylesheet, rules/cssrules are null if its from a different domain. A workaround, probably not acceptable in most cases, is to get the contents of the stylesheet via ajax request, and append the response to a style tag in document head. – CodeToad Aug 26 '13 at 15:24
  • 1
    Although [interesting answer here](http://stackoverflow.com/a/18471848/1028230), at serg's first linked question: `The only real solution to this problem is to CORS load your CSS in the first place. By using a CORS xmlHTTPRequest to load the CSS from an external domain, and then injecting the responseText... ` – ruffin Nov 03 '15 at 20:19
0

I fixed my version of the issue by changing the url from http:// to https://. Doh!

Kudit
  • 4,212
  • 2
  • 26
  • 32
0

First, content scripts can't access cross-origin scripts. Second, you can fetch cross-origin scripts from the background service worker (MV3) in a Chrome Extension.

What I am doing in my Chrome Extension's content script is using this to iterate over the stylesheets and sending the failed stylesheet link to the background script in the catch statement

let styleSheets = [];
// Iterating over all stylesheets
[...document.styleSheets].map(function(styleSheet) {
  try {
    [...styleSheet.cssRules].map(function(cssRule) {
      styleSheets.push(cssRule);
    });
  } catch (e) {
    styleSheets.push(null);
    // Send failed stylesheets to service worker from here
  }
});

And in the background server worker, using this function to get the stylesheet.

fetch(styleSheetUrl)
  .then((response) => {
    if (response.status >= 200 && response.status < 300) return response.text();
    else return false;
  })
  .then((styleSheet) => {
    console.log(styleSheet);
  });