使用.cssRules访问跨域样式表

当我尝试访问外部域上托管的一些CSS文件时,我在Firebug中收到此错误:

Security error" code: "1000 rules = styleSheets[i].cssRules; 

我使用的代码是:

 $(document).ready(function () { $("p").live('mousedown', function getCSSRules(element) { element = $(this); var styleSheets = document.styleSheets; var matchedRules = [], rules, rule; for (var i = 0; i < styleSheets.length; i++) { rules = styleSheets[i].cssRules; for (var j = 0; j < rules.length; j++) { rule = rules[j]; if (element.is(rule.selectorText)) { matchedRules.push(rule.selectorText); } } } alert(matchedRules); }); }); 

除了移动同一域上的所有CSS文件之外,有没有办法解决这个问题?

这个问题的唯一真正解决方案是CORS首先加载你的CSS。 通过使用CORS XMLHttpRequest从外部域加载CSS,然后通过以下方式将responseText(在本例中实际为responseCSS)注入到页面中:

 function loadCSSCors(stylesheet_uri) { var _xhr = global.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(); } 

这样,浏览器将CSS文件解释为来自与主页面响应相同的原始域,现在您可以访问样式表的cssRules属性。

从2013年开始,您可以在 -Element上设置“crossorigin”属性,以通知浏览器此CSS受信任( Mozilla , W3 )。 为此,托管CSS的服务器必须设置Access-Control-Allow-Origin: *标头。

之后,您可以通过Javascript访问其规则。

如果您可以控制托管外部样式表的域,则可能有助于添加适当的Access-Control-Allow-Origin标头 。

 Access-Control-Allow-Origin: http://stylesheet-user.example.com 

我写了一个小函数,将解决包括FF在内的跨浏览器的加载问题。 关于GitHub的评论有助于解释用法。 完整代码位于https://github.com/srolfe26/getXDomainCSS 。

免责声明:以下代码依赖于jQuery。

有时候,如果你从一个你无法控制CORS设置的地方拉CSS,直到获得带有标签的CSS,那么要解决的主要问题就是知道你的被调用CSS何时被加载并准备使用。 在较旧的IE中,您可以在加载CSS时运行on_load侦听器。

较新的浏览器似乎需要过时的轮询来确定何时加载文件,并在确定何时满足负载时遇到一些跨浏览器问题。 请参阅下面的代码以了解其中的一些怪癖。

 /** * Retrieves CSS files from a cross-domain source via javascript. Provides a jQuery implemented * promise object that can be used for callbacks for when the CSS is actually completely loaded. * The 'onload' function works for IE, while the 'style/cssRules' version works everywhere else * and accounts for differences per-browser. * * @param {String} url The url/uri for the CSS file to request * * @returns {Object} A jQuery Deferred object that can be used for */ function getXDomainCSS(url) { var link, style, interval, timeout = 60000, // 1 minute seems like a good timeout counter = 0, // Used to compare try time against timeout step = 30, // Amount of wait time on each load check docStyles = document.styleSheets // local reference ssCount = docStyles.length, // Initial stylesheet count promise = $.Deferred(); // IE 8 & 9 it is best to use 'onload'. style[0].sheet.cssRules has problems. if (navigator.appVersion.indexOf("MSIE") != -1) { link = document.createElement('link'); link.type = "text/css"; link.rel = "stylesheet"; link.href = url; link.onload = function () { promise.resolve(); } document.getElementsByTagName('head')[0].appendChild(link); } // Support for FF, Chrome, Safari, and Opera else { style = $(' 

我在firefox和chrome下遇到过类似的问题。 我已经通过向我的域添加一个包含外部域css的css文件以一种苛刻的方式解决了它,如下所示:

  

这很快但很脏。 建议将所有css文件保留在您的域中。

如果这会触发你,因为你的某些CSS可能来自其他地方而不是你感兴趣的那些,请使用try … catch块,如下所示:

 function cssAttributeGet(selectorText,attribute) { var styleSheet, rules, i, ii; selectorText=selectorText.toLowerCase(); if (!document.styleSheets) { return false; } for (i=0; i