Cannot Access CSSrules from Local CSS File in Chrome 64

Cannot access cssRules from local css file in Chrome 64

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.

cannot access rules in external CSSStyleSheet

As of Chrome 64, new CORS rules are enforced for stylesheets. You'll need to use a local development server to do local testing of functionality that depends on the CSS Object Model. For details, see Cannot access cssRules from local css file in Chrome.

Cannot Access cssRules for Stylesheet CORS

I ended up finding a solution...

All thanks to Paulo Belo from this link Uncaught DOMException: Failed to read the 'cssRules' property

stylesheet.crossOrigin = "anonymous" solved my problem giving me access to the cssRules.

Sample Image
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin

Note this fix does not work with existing stylesheets that are throwing this error.

Exception: DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules at CSSStyleSheet.s

This fix only works for your own uploaded sheets or in my case the ones from my CDN.

Sample Image

htmlToImage Chrome 64 SecurityError: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules

I just fixed this error.

Forked the lib and made a pull request. Until it gets merged, you can use the forked repo: https://github.com/kmap-io/html-to-image

by replacing the target of html-to-image in your package.json with:

"html-to-image": "git+https://github.com/kmap-io/html-to-image.git"


About the bug

Chrome is complaining (throws an error) about trying to read a property that does not exist. Firefox also complains, but they only throw a warning, instead of an error. The fix consists of replacing

if (sheet.cssRules) {
...

with

if (sheet.hasOwnProperty('cssRules')) {
...

There is no downside (i.e.: when cssRules exists on sheet - which is a stylesheet - the script iterates through the rules and adds them to document, as supposed to).


How to patch (until it gets merged).

For some reason, simply replacing the library's repo with the fork in which I committed the change doesn't work for this package. I asked the lib's author to add instructions on how to build after a pull-request, as they state in the readme pull requests and contributions are welcome. Until then, here's how to apply the fix using patch-package:

  • add "prepare": "patch-package" inside scripts, in your project's package.json
  • npm i patch-package --save-dev
  • In node_modules/html-to-image/lib/embedWebFonts.js, change line 7 from
try {

to

if (sheet.hasOwnProperty('cssRules')) try {
  • npx patch-package html-to-image

If you have a deployment script that builds your project from scratch, you'll need to apply the patches right before you call npm run build (or similar, depending on your stack):

git apply --ignore-whitespace patches/*.patch

That's about it.

When the fix will be merged, you'll need to run:

npx patch-package html-to-image --reverse

Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet'

This was a good story and a new 'gotcha' for web developers, so I just had to share:

Chrome 64.0.3282.0 (released January 2018, full change list) introduced a change to security rules for stylesheets. I'm irritated that 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.

All that said, why was this issue showing up in App Lab? We shouldn't experience any CORS issues, because we only load stylesheets from our own origin:

Chrome network tab showing all CSS requested from the affected page

The final clue was that we couldn't reproduce this issue in a private tab. We started looking at Chrome extensions and realized that some affected users had the Loom Video Recorder extension enabled, which seems to inject its own CSS into the page. Since our (naïve) function was iterating through all loaded stylesheets, it was attempting to access this stylesheet injected by the extension and thus causing the CORS error.

That said, there's still some open issues and debate around this change in Chrome:

  • 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.

To fix our problem, we just tore out the entire function. We don't support IE9 anymore, and we know all of our supported browsers handle media queries properly.

Related (but not quite duplicate) questions:

  • cannot access rules in external CSSStyleSheet
  • Cannot access cssRules from local css file in Chrome

Chrome 64 Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': Cannot access StyleSheet to insertRule

We believe this commit to Chromium to be the root cause of our issue:

Update behavior of CSSStyleSheet to match spec for Security origin

The quick solution for us was to simply reorder the CSS. It seems that previously the culprit plugin was inserting CSS rules to this remote CSS:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400,700">

Simply reordering our stylesheets to ensure a script from our site was in first position (document.styleSheets[0]), fixed the issue:

<link type="text/css" rel="stylesheet" href="/Public/js/jquery-ui/jquery-ui.css" />
<link type="text/css" rel="stylesheet" href="/Public/js/jquery-ui/jquery-ui.theme.min.css" />
<link type="text/css" rel="stylesheet" href="/Public/css/msgPop.css" />
<link type="text/css" rel="stylesheet" href="/Public/js/select2/select2.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400,700">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">


Related Topics



Leave a reply



Submit