Question

I am trying to create a bookmarklet that reads a website's CSS media queries and adds CSS rules depending on the result. But I usually can't even access a page's CSS file. Here's what I've tried so far (this is all in-page JS code that assumes the presence of JQuery):

var styleSheet = document.styleSheets.item(0);
var rules = styleSheet.cssRules;

This fails with

Exception: The operation is insecure.

I'm using Firefox and think that this approach usually works in other browsers, but I need this to work across browsers. I can't enable JSONP or CORS on the server because I don't have access to the server. So I take a different tack.

$.ajax({
  url: styleSheet.href,
  type: "GET",
  success: function(data, textStatus, jqXHR) {
    console.log('data: '+data+", textStatus: "+textStatus+"\nObject: "+data);
  },
  error: function(jqXHR, textStatus, error) {
    console.error("Failed. jqXHR: "+JSON.stringify(jqXHR)+"\ntextStatus:"+textStatus+"\nerror: "+error);
  }
});

This returns 200 every time, but works very infrequently, and gives me no information of why it fails:

Failed. jqXHR: {"readyState":0,"responseText":"","status":0,"statusText":"error"}

textStatus: error

error:

(I also tried a plain $.get, but hoped the above would tell me why it was failing). If you know how to get more info out of a request, let me know.

Because I'm looking for media queries, I need access to the CSS file and can't just look at elements' calculated CSS.

I'm not trying to change the CSS file, just apply apply new CSS to elements, so I don't see why it should be considered insecure.

Finally, the fact that I can clearly see a page's CSS in the style editor or by navigating to the URL I get from styleSheet.href means that it should be accessible programatically. If possible, a solutions that works on https pages as well would be amazing.

Was it helpful?

Solution

I believe that (in FF at least) you can't read styleSheets cross domain using unprivileged Javascsript (like in bookmarklets). It is the same limitation as AJAX. There is no "direct" solution. You'll have to work around it by using a proxy or by using privileged javascript (like in an addon or userscript).

Here is a related snippet of code I have used which accepts the limitation.

function getStyle() {
  var r = [];
  for ( var i=0; i < d.styleSheets.length; i++ ) {
    try { // trying to read cross domain sheets can throw error
      var classes = d.styleSheets[i].rules || d.styleSheets[i].cssRules;
      for ( var x=0; x < classes.length; x++ ) r.push(classes[x].cssText || classes[x].style.cssText);
    } catch(e){}
  }
  return r;
}

OTHER TIPS

The operation is insecure because of browser security policies. Browsers will restrict you to the Same Origin Policy, unless Cross Origin Resource Sharing is enabled on the requested page. This means that you cannot request resources from another webpage (i.e. stylesheets) unless it explicitly allows you to.

You can get around this by writing your bookmarklet as a browser extension, which is not restricted to the Same Origin Policy. For example, Chrome Extensions can make Cross Origin XMLHttpRequests (http://developer.chrome.com/extensions/xhr.html).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top