Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails silently on CSS loaded from subdomain #6

Closed
cmcclure opened this issue Apr 7, 2014 · 13 comments
Closed

Fails silently on CSS loaded from subdomain #6

cmcclure opened this issue Apr 7, 2014 · 13 comments

Comments

@cmcclure
Copy link

cmcclure commented Apr 7, 2014

Due to the Cross Origin Policy, documents.stylesheets[x].cssRules returns null for stylesheets loaded from a different domain, including subdomains. This means the script has nothing relevant to process, and simply doesn't work. This is especially frustrating for people like myself who serve static content like CSS, JS, and images from a CDN.

I've been looking around and haven't found a fix yet. Possibly CORS, but I'm still testing things out. Do you have any ideas?

@rodneyrehm
Copy link
Owner

Until now I didn't even realise that SOP had any effect on CSSOM. Does that happen in all browsers? Without having fully read the spec (whichever version…), this feels like a browser bug.

@rodneyrehm
Copy link
Owner

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

Derp. There goes that plan. I think I'm just going to take the output of your script while I'm testing on localhost and save it off as an ios specific rule set. Not very flexible, but unless you can think of another work around, I think this is what I have to do.

@rodneyrehm
Copy link
Owner

Have you tried seting CORS headers for those resources (if only to test)? A static output won't do you any good, as you don't know the viewport's dimensions ahead of time.

What we could discuss, though, is a way to identify and extract the offending rules. You'd likely want to do that statically with rework. Simply filter out anything that doesn't use viewport units and save the result to another file. That one could then be loaded - on iOS only - from the "proper" origin.

(honestly, I'd try the CORS thing first…)

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

Yeah, I was going to try and get tricky with some media queries and all the permutations of ios devices. (Fortunately, there aren't many variations)

I tried just adding the access control headers, but I haven't run a full xhr implementation. I'll run some tests and let you know what I find.

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

OK, Here's how I got it to work...
In some JS, I grab the stylesheet with a CORS AJAX request and insert it into the Head as a second instance of the stylesheet. After that I call your init function. It seems to work. If you have any suggestions on streamlining it, I'd be all ears. Maybe we can wrap this functionality into buggyfill itself.

// iOS "Polyfill" for VH weirdness
// https://github.com/rodneyrehm/viewport-units-buggyfill
// JS can't read styles on cross domain stylesheets, so we
// ajax it in a second time and append to the head
function createCORSRequest(method, url) {
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {
        // XHR for Chrome/Firefox/Opera/Safari.
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined") {
        // XDomainRequest for IE.
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        // CORS not supported.
        xhr = null;
    }
    return xhr;
}

// Make the actual CORS request.
function makeCorsRequest() {
    var url = 'http://playground.localhost/init.css',
        xhr = createCORSRequest('GET', url);
    if (!xhr) {
        // console.log('CORS not supported');
        return;
    }

    // Response handlers.
    xhr.onload = function() {
        // console.log('Stylesheet reloaded');

        var styleNode = document.createElement('style');
        styleNode.textContent = xhr.responseText;
        document.head.appendChild(styleNode);

        window.viewportUnitsBuggyfill.init();
    };

    xhr.onerror = function() {
        // console.log('AJAX CORS request failed');
    };

    xhr.send();
}
if (/ip.+mobile.+safari/i.test(window.navigator.userAgent)){
    makeCorsRequest();
}

@rodneyrehm
Copy link
Owner

I just verified that only setting the CORS headers won't "magically" make the CSSOM grant access to the content. bummer. So we'll have to check for stylesheet.ownerNode.nodeName.toLowerCase() === 'link' && origin(stylesheet.href) !== origin(location.href) and replace that <link> with a <style> containing the referenced content. This causes another re-style and mandates async operation.

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

I think we can fold your check in with the chuck I posted above to reach global stylesheet nirvana.

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

Also, I don't think you need to replace the link. If you just add the <style> as a duplicate, it should work fine. No visible refresh that way.

@rodneyrehm
Copy link
Owner

A restyle is happening, no way around that. if that triggers a layout and subsequently a paint is up to the browser. You'd want to remove the <link> in order to reduce the number of selectors the browser has to test for each DOM mutation. Removing the <link> also means the memory can be freed. In a mobile context, you really don't want to waste more resources than absolutely necessary.

I hope to get to adding this tomorrow evening.

@cmcclure
Copy link
Author

cmcclure commented Apr 8, 2014

Thanks for your help on this one. This bug was driving me crazy for about two full days. Since we don't use the cdn on localhost or staging, it was only showing up in production. Everybody's least favorite type of bug. I was happy that I finally tracked down the problem, and then immediately bummed that there wasn't a simply solution. :)

@rodneyrehm
Copy link
Owner

Thanks for the find. This would've bitten me sooner or later.

@cmcclure
Copy link
Author

cmcclure commented Apr 9, 2014

No problem.

@rodneyrehm rodneyrehm mentioned this issue Apr 30, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants