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

Fix bug where styles have their media queries removed on IE #238

Closed
wants to merge 1 commit into from

Conversation

reklawnos
Copy link
Contributor

@reklawnos reklawnos commented May 5, 2017

In IE 9, appending two styles with media queries to a StyleSheet's cssText property results in the first style's media query being removed and that first style will always apply without the query.

For example:

var styleTag = document.createElement('style');
document.body.appendChild(styleTag);
styleTag.styleSheet.cssText +=
  '@media (min-width: 500px) { body { background-color: blue; } }';
styleTag.styleSheet.cssText +=
  '@media (min-width: 700px) { body { background-color: red; } }';

Causes the body element to be red for window widths ≥ 700px, but it is blue otherwise, even at widths < 500px.

This change adds a styleString variable that keeps track of the contents of the current styleTag, and updates the cssText content with styleString instead of appending to it with +=.

Here's a JS Bin that demonstrates the issue, which includes a commented-out solution. Note that the JS Bin won't work outside of IE. If you don't want to open up IE you can take a look at these gifs, recorded on IE 9:

Using styleSheet.cssText

broken example

Using innerText

working example

@khanbot
Copy link

khanbot commented May 5, 2017

Hey @reklawnos,

Thanks for the PR! Mind signing our Contributor License Agreement?

When you've done so, go ahead and comment [clabot:check] and I'll check again.

Yours truly,
khanbot

@reklawnos reklawnos force-pushed the fix-media-queries-ie branch from 466b29f to 6fb6555 Compare May 5, 2017 21:19
@reklawnos
Copy link
Contributor Author

[clabot:check]

@khanbot
Copy link

khanbot commented May 5, 2017

CLA signature looks good 👍

src/inject.js Outdated
@@ -47,7 +47,7 @@ const injectStyleTag = (cssContents /* : string */) => {

if (styleTag.styleSheet) {
// $FlowFixMe: legacy Internet Explorer compatibility
styleTag.styleSheet.cssText += cssContents;
styleTag.innerText += cssContents;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you do any profiling to see what the performance impact this might be?

Also, I wonder if we should be using insertRule() instead?

https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule

@lencioni lencioni added the bug label May 8, 2017
In IE 9, appending two styles with media queries to a `StyleSheet`'s
`cssText` property results in the first style's media query being
removed and that first style will always apply without the query.

For example:

```
var styleTag = document.createElement('style');
document.body.appendChild(styleTag);
styleTag.styleSheet.cssText +=
  '@media (min-width: 500px) { body { background-color: blue; } }';
styleTag.styleSheet.cssText +=
  '@media (min-width: 700px) { body { background-color: red; } }';
```

Causes the body element to be red for window widths ≥ 700px, but it is
blue otherwise, even at widths < 500px.

This change adds a `styleString` variable that keeps track of the
contents of the current `styleTag`, and updates the `cssText` content
with `styleString` instead of appending to it with `+=`.
@reklawnos reklawnos force-pushed the fix-media-queries-ie branch from 6fb6555 to 1e18722 Compare May 9, 2017 21:54
@reklawnos
Copy link
Contributor Author

@lencioni I changed the approach a bit so that we're still using cssText. innerText had a roughly 10x performance penalty, and since AFACT this issue only affects styles with media queries that's not really acceptable.

I found that insertRule had around the same performance as the current cssText approach in IE, but it appeared to be quite a bit more performant than the appendChild approach in Chrome/Firefox. Its performance is pretty consistent, whereas appendChild gets quite a bit slower every time new styles are added.

There's a fair amount of work that'd need to be done to get insertRule to function. There was some work done to use insertRule in #83 and #157, and some discussion in #76. Looks like it would require some refactoring and changes to several tests. insertRule also throws when you pass it selectors the browser doesn't recognize, e.g. .foo:-moz-placeholder in Chrome. We could probably get some insight from looking at mattkrick's fork of Aphrodite which uses insertRule.

Copy link
Collaborator

@lencioni lencioni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR message needs to be updated.

Would you be interested in pairing with me on the insertRule stuff sometime?

// $FlowFixMe: legacy Internet Explorer compatibility
styleTag.styleSheet.cssText += cssContents;
styleTag.styleSheet.cssText = styleString;
Copy link
Collaborator

@lencioni lencioni May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if you could avoid managing styleString by doing this instead?

styleTag.styleSheet.cssText = styleTag.innerText + cssContents;

With your current approach I mostly worry about something else modifying the stylesheet and then that getting blown away (in addition to the extra bookkeeping complexity). Doesn't seem super likely, but if we can trivially avoid it might as well, right?

Need to see if that is still okay for performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should avoid having to keep track of styleString if possible, but that solution won't quite work because innerText doesn't get updated when cssText is altered.

reklawnos added a commit to reklawnos/aphrodite that referenced this pull request May 12, 2017
Instead of appeding a new text node to a style tag or appending to the
`cssText` property of the stylesheet (which broke media queries in IE as
documented in Khan#238), use `insertRule` to add CSS rules to the `style`
element.

This change requires styles to be generated as an array of strings with
one rule per string, rather than a single large string that contains
multiple rules.
Trolleymusic pushed a commit to Trolleymusic/aphrodite that referenced this pull request Jul 25, 2017
Instead of appeding a new text node to a style tag or appending to the
`cssText` property of the stylesheet (which broke media queries in IE as
documented in Khan#238), use `insertRule` to add CSS rules to the `style`
element.

This change requires styles to be generated as an array of strings with
one rule per string, rather than a single large string that contains
multiple rules.
reklawnos added a commit to reklawnos/aphrodite that referenced this pull request Jan 30, 2018
Instead of appeding a new text node to a style tag or appending to the
`cssText` property of the stylesheet (which broke media queries in IE as
documented in Khan#238), use `insertRule` to add CSS rules to the `style`
element.

This change requires styles to be generated as an array of strings with
one rule per string, rather than a single large string that contains
multiple rules.
lencioni pushed a commit that referenced this pull request Jan 31, 2018
Instead of appeding a new text node to a style tag or appending to the
`cssText` property of the stylesheet (which broke media queries in IE as
documented in #238), use `insertRule` to add CSS rules to the `style`
element.

This change requires styles to be generated as an array of strings with
one rule per string, rather than a single large string that contains
multiple rules.
@lencioni
Copy link
Collaborator

Closing, as I believe this was fixed by #240.

@lencioni lencioni closed this Jan 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants