当我尝试访问外部域上托管的一些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文件之外,还有办法解决这个问题吗?
答案 0 :(得分:12)
这个问题的唯一真正解决方案是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属性。
答案 1 :(得分:10)
截至2013年,您可以在<link>
- 元素上设置“crossorigin”属性,以通知浏览器此CSS受信任(Mozilla,W3)。为此,托管CSS的服务器必须设置Access-Control-Allow-Origin: *
标题。
之后,您可以通过Javascript访问其规则。
答案 2 :(得分:2)
如果您可以控制托管外部样式表的域,则可能有助于添加appropriate Access-Control-Allow-Origin header。
Access-Control-Allow-Origin: http://stylesheet-user.example.com
答案 3 :(得分:2)
我写了一个小函数,它将解决包括FF在内的跨浏览器的加载问题。关于GitHub的评论有助于解释用法。完整代码位于https://github.com/srolfe26/getXDomainCSS。
免责声明:以下代码依赖于jQuery。
有时候,如果您从一个无法控制CORS设置的地方提取CSS,直到获得带有<link>
标记的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 = $('<style>')
.text('@import "' + url + '"')
.attr({
// Adding this attribute allows the file to still be identified as an external
// resource in developer tools.
'data-uri': url
})
.appendTo('body');
// This setInterval will detect when style rules for our stylesheet have loaded.
interval = setInterval(function() {
try {
// This will fail in Firefox (and kick us to the catch statement) if there are no
// style rules.
style[0].sheet.cssRules;
// The above statement will succeed in Chrome even if the file isn't loaded yet
// but Chrome won't increment the styleSheet length until the file is loaded.
if(ssCount === docStyles.length) {
throw(url + ' not loaded yet');
}
else {
var loaded = false,
href,
n;
// If there are multiple files being loaded at once, we need to make sure that
// the new file is this file
for (n = docStyles.length - 1; n >= 0; n--) {
href = docStyles[n].cssRules[0].href;
if (typeof href != 'undefined' && href === url) {
// If there is an HTTP error there is no way to consistently
// know it and handle it. The file is considered 'loaded', but
// the console should will the HTTP error.
loaded = true;
break;
}
}
if (loaded === false) {
throw(url + ' not loaded yet');
}
}
// If an error wasn't thrown by this point in execution, the stylesheet is loaded, proceed.
promise.resolve();
clearInterval(interval);
} catch (e) {
counter += step;
if (counter > timeout) {
// Time out so that the interval doesn't run indefinitely.
clearInterval(interval);
promise.reject();
}
}
}, step);
}
return promise;
}
答案 4 :(得分:1)
如果这会触发您,因为您的某些CSS可能来自其他地方而不是您感兴趣的位,请使用try ... catch块,如下所示:
function cssAttributeGet(selectorText,attribute) {
var styleSheet, rules, i, ii;
selectorText=selectorText.toLowerCase();
if (!document.styleSheets) {
return false;
}
for (i=0; i<document.styleSheets.length; i++) {
try{
styleSheet=document.styleSheets[i];
rules = (styleSheet.cssRules ? styleSheet.cssRules : styleSheet.rules);
for (ii=0; ii<rules.length; ii++) {
if (
rules[ii] && rules[ii].selectorText &&
rules[ii].selectorText.toLowerCase()===selectorText &&
rules[ii].style[attribute]
){
return (rules[ii].style[attribute]);
}
}
}
catch(e){
// Do nothing!
};
}
return false;
}
答案 5 :(得分:1)
我在firefox和chrome下有类似的问题。我已经通过向我的域添加一个包含外部域css的css文件以一种苛刻的方式解决了它,如下所示:
<style type="text/css">
@import url("https://externaldomain.com/includes/styles/cookie-btn.css");
</style>
这很快但很脏。建议将所有css文件保留在您的域中。
答案 6 :(得分:0)