Use javascript to get CSS rules from an external stylesheet

Asked

Viewed 454 times

3

I’m getting the style sheet rules for this situation addressed in this question.

But if you use internal CSS (with tag <style>) I correctly get the declared styles, as you can see in the following example:

var sheets = document.styleSheets;

for (var i in sheets) {
  var rules = sheets[i].rules || sheets[i].cssRules;
  for (var r in rules) {
    if (rules[r].selectorText) {
      // para imprimir no DOM
      document.body.appendChild(document.createTextNode(rules[r].cssText));
      document.body.appendChild(document.createElement("br"));
    }
  }
}
p {
  color: red;
}
h1 {
  font-size: 16pt;
}

I already use an external CSS file, the document.styleSheets even brings the style sheet, but the rules (rules or cssRules) are null, and the attribute href is with the value of url external pointing to the file. As can be seen in the following example:

var sheets = document.styleSheets;

for (var i in sheets) {
  if (sheets[i] instanceof CSSStyleSheet) {
    console.log(sheets[i]);
  }
  var rules = sheets[i].rules || sheets[i].cssRules;
  for (var r in rules) {
    if (rules[r].selectorText) {
      // para imprimir no DOM
      document.body.appendChild(document.createTextNode(rules[r].cssText));
      document.body.appendChild(document.createElement("br"));
    }
  }
}
<!-- Utilizei o CSS do bootstrap por ser um CSS confiável externo para demonstrar meu problema -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.css">
<p>Verifique o console para observar as saídas!</p>

Question

Is there any way to get CSS rules using external CSS file (Example 2), just like with internal CSS (Example 1)?

Testing here I noticed that in Firefox, this is working, but in Chrome, IE10 and Opera not.

  • Are you not trying to get the rules before the CSS is finished loading and parsing? Try running this on window.onload.

  • @bfavaretto, I believe this is not the problem, because I am running it from a button, and at that moment the page is already stylized, so the CSS is already loaded.

  • 1

    I suspect this is due to a permission issue when accessing a style sheet on another domain. A MDN goes so far as to say that this can make an exception (which I have not seen happen in Chrome). You have tested with a CSS in the same domain as your application?

  • @bfavaretto, to tell you the truth I’m just testing the local application, I have no knowledge whether this is considered same domain or not?

  • 1

    Yes, as long as it is referred to the same way in the browser URL and CSS (e.g., "localhost" or "127.0.0.1" on both), and that you are not loading the page withfile:///.

  • @bfavaretto, I will install an application server here because I am running on file:///, like you said. =(

  • @bfavaretto, you were right this seems to be a different domain loaded style/CSS problem as quoted in the reference you quoted from MDN, where testing here on an application server, on localhost or 127.0.0.1. It seems that this works as expected. Thanks for the tip. And if you think it is feasible to create an answer, it would be interesting for further research.

Show 2 more comments

1 answer

1


As explained by Jordan M Alperin,

The only real solution to this problem is to load your CSS into CORS (Cross Origin Resource Sharing) mode. Through an xmlHTTPRequest CORS you load the CSS from an external domain, and then inject the responseText (actually a responseCSS in this case) into the page. Something similar to the code below:

function carregarCSSExterno(stylesheet_uri) {
    var _xhr = window.XMLHttpRequest;
    var has_cred = false;

    try {has_cred = _xhr && ('withCredentials' in (new _xhr()));} catch(e) {}

    if (!has_cred) {
        console.error('CORS not supported');

        return;
    }

  var xhr = new _xhr();
  xhr.open('GET', stylesheet_uri);
  xhr.onload = function() {

  xhr.onload = xhr.onerror = null;

  if (xhr.status < 200 || xhr.status >=300) {
      console.error('style failed to load: ' + stylesheet_uri)
  } else {
      var style_tag = document.createElement('style');
      style_tag.appendChild(document.createTextNode(xhr.responseText));
      document.head.appendChild(style_tag);
  };

  xhr.onerror = function() {
      xhr.onload = xhr.onerror = null;
      console.error('XHR CORS CSS fail:' + styleURI);
  };
}

  xhr.send();
}

// Após chamar essa função o estilo deverá ter sido adicionado para sua
// página e deverá estar preenchido com todas as regras CSS.
carregarCSSExterno("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.css");

As well as elucity by Jordan M Alperin:

This way the CSS files will be interpreted by the browser as coming from the same origin domain as the main response page and now you will have access to the cssRules properties of your style page.

  • Um, I got Ulysses, it’s a good alternative, basically it makes external css internal, so from that point I can treat it as internal css. This would eliminate the CORS problem. + 1.

  • Yes @Fernando. This solution worked for you?

  • I actually saw that it works, but I didn’t use it in my real application because the solution of my real application was the last comment of bfavaretto to the question, where I was running via "file:///" instead of on an application server, by "localhost" or "127.0.0.1", which generated CORS in a local resource, but its solution goes beyond that, making any external css feature in place. I’ll take a closer look here and maybe accept your answer to the problem.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.