Cannot access cssRules from local css file in Chrome 64
Here's a simple example of the problem:
<html>
<head>
<link rel='stylesheet' href='myStyle.css'>
<script>
window.onload=function(){
try{
alert(document.styleSheets[0]); // works
alert(document.styleSheets[0].cssRules); // doesn't even print undefined
}catch(e){alert(e);} // catch and alert the error
}
</script>
</head>
<body>
</body>
</html>
myStyle.css body{background-color:green;}
The script works fine with <style></style>
Solutions:
- Works when files are online/localhost.
- Works with other browsers. (i.e. Internet Explorer, Microsoft Edge, Firefox)
- chrome --allow-file-access-from-files
Solution 1:
TL;DR: As of Chrome 64 you'll need to use a local development server to test functionality that depends on the CSS Object Model.
Accessing CSS rules in a stylesheet loaded from the local filesystem violates a Cross-Origin Resource Sharing (CORS) policy - but Chrome didn't enforce this until recently, and other browsers don't seem to enforce it yet.
Chrome 64.0.3282.0 (released January 2018, full change list) includes a change to security rules for stylesheets. I couldn't find this change in any changelog less detailed than the full commit list.
Commit a4ebe08 in Chromium is described:
Update behavior of CSSStyleSheet to match spec for Security origin
Spec is here: https://www.w3.org/TR/cssom-1/#the-cssstylesheet-interface
Updated: the following methods now throw a SecurityError if the style sheet is not accessible:
- cssRules() / rules()
- insertRule()
- deleteRule()
This commit is a fix for the bug Security: Inconsistent CORS implementation regarding CSS and the link element. The linked W3C spec describes in detail where use of the CSS Object Model requires same-origin access.
This is a real security constraint and the solution you posted (online/localhost) is probably the most typical workaround. For more information check out MDN's How do you set up a local testing server? - it discusses why and how to use a local development server to avoid CORS issues.
That said, there's still some open issues and debate around this change.
-
This comment on the original security bug complains that the only way now to detect that the stylesheet is not accessible from JavaScript is with a
try/catch
. - A Chromium bug opened January 23rd (document.styleSheets.cssRules is null even with Access-Control-Allow-Origin: *) suggests there may be an implementation issue with the new security rule that breaks certain workarounds.
- The spec being implemented seems pretty stable, but it still has "Working Draft" status so who knows where it will land and what other browsers will implement.