-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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 styles to prevent subtle diffing bugs, add support for vendor prefixing #6701
Conversation
We've said in the past that we might want to support |
@spicyj If we wanted to do that, we could support both within React. Margin would just be a css style that is known to take multiple values (ie. disable vendor prefixing logic for those known styles). That is, if we do desire to support that behavior. So I'd say these approaches aren't mutually exclusive. |
|
Ok, well, as per discussion, it sounds like we'll go with something like |
aa9a68f
to
c4463a1
Compare
@jimfb updated the pull request. |
Could we consider a different name for E.g. The naming indicates I should write If this method is specifically for CSS vendor prefixes, maybe something like |
We can always bikeshed on the name if we take this route. I also dislike |
@zpao proposal? I'm very open to ideas. I'm not attached to this notation/name, but I would like to find something that is acceptable to everyone so we can drive this to completion. |
Haven't thought any more about a name beyond that multi seems overly vague. Regardless of that, can we pull this apart so we can consider the 2 pieces of this distinctly.
|
@@ -62,6 +63,10 @@ var React = { | |||
only: onlyChild, | |||
}, | |||
|
|||
CSS: { | |||
multi: CSSPropertyOperations.multi, | |||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would definitely be a ReactDOM API (nothing in isomorphic/
should require anything in renderers/
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd actually even argue that this shouldn't be a part of React's API and should live in a little helper/addon module somewhere on NPM.
a8d7719
to
40c3842
Compare
@@ -236,6 +249,10 @@ var CSSPropertyOperations = { | |||
} | |||
}, | |||
|
|||
multi: function() { | |||
arguments.__isMultiCssValue = true; | |||
return arguments; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn’t leaking arguments
bad in general?
https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worse than copying the values in to a new array? Happy to change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, fixed.
@jimfb updated the pull request. |
From my understanding we really really should benchmark real-life cases to see whether updating |
Maybe worth running some demos from @chenglou’s react-motion. |
Just an addition to @syranide's excellent point about the performance benefit of consolidating style changes into a single DOM operation: it's also worth noting that setting Benchmark.js Test (toggles 4 property values) |
@developit My point was the exact opposite, that IMHO it's pointless to throw around raw numbers here. It's a question of whether or not performance is acceptable with PS. Your benchmark fails to consider the cost of serializing the styles to supplied to |
Perhaps the better pairing is whichever more closely matches React's preferred format for the style attribute in JSX. If that's heading in the direction of objects by default, then I can see properties making more sense. |
Let's do a math exercise. I'm getting ~45k/ops on IE11 according to the benchmark. 45k / 60 = 750 ops/frame, that's a big number, but it's not a huge number. Consider that you may have more complex styles, lots of elements animating (all the different parts of a button may animate, so a button is not "just one thing"), need some leeway to maintain fluid animation, cache-misses, real-life overheads and there being other significant costs besides just setting styles then it seems to me that achieving fluid 60 FPS is not trivial, performance is important! So if we go with IMHO React has wisely chosen the "best worst-case" route, it's not the fastest, but it's always fast enough. In this case that is setting via property considering the vast improvements in the worst-case, or so it seems to be at least. |
It's probably worth mentioning that the benchmark is toggling, so all those numbers should be adjusted by a factor of 2. Also, in Chrome I'm seeing ~200k ops/sec, which is over 3000 ops/frame. In reality, I don't think there is much of an argument to be made for one approach over the other given that the benchmark I linked doesn't actually show the values for differing numbers of properties. It seems that it'd be worth testing the performance stratified by property count - if it turns out (as seems likely) that cssText is faster for large numbers of properties, wouldn't it be reasonable to switch between the two implementations depending on that factor? Also, do you have an example showing that mutating |
Optimizing for the "best best-case" is not really relevant.
That's not what I said, the two have very difference performance characteristics and it does not come down to the number of properties.
I never said that. esbench broke it seems. Anyway, run the following bench to see what I mean. It shows 35k/ops for cssText and 130k/ops for properties. So to put it in perspective; if I get to choose between having 20% faster in the best-case and 350%+ slower in the worst-case or vice versa then I would optimize for the worst-case. EDIT: Yes it's an imperfect benchmark. let node = document.createElement('div');
document.body.appendChild(node);
// hoist style definitions so we're not allocating in the tests
let styles = [
'color:blue; margin:2px 3px; padding:5px; position:relative;',
'color:red; margin:2px 3px; padding:5px; position:relative;',
'color:blue; margin:2px 3px; padding:5px; position:relative;'
];
let stylesObj = [
{ color:'blue', margin:'2px 3px', padding:'5px', position:'relative' },
{ color:'red' },
{ color:'blue' }
];
function setViaCssText(css) {
node.style.cssText = css;
}
function setViaPropertiesAssigned(properties) {
Object.assign(node.style, properties);
} setViaCssText(styles[0]);
setViaCssText(styles[1]);
setViaCssText(styles[2]);
setViaCssText(styles[1]);
setViaCssText(styles[2]);
setViaCssText(styles[1]); setViaPropertiesAssigned(stylesObj[0]);
setViaPropertiesAssigned(stylesObj[1]);
setViaPropertiesAssigned(stylesObj[2]);
setViaPropertiesAssigned(stylesObj[1]);
setViaPropertiesAssigned(stylesObj[2]);
setViaPropertiesAssigned(stylesObj[1]); |
Didn't read everything said in this thread, in response to @spicyj
I also want to add something like this to jss and it has already support for fallbacks from the very beginning. So I think a good way would be to do something like this
It is more verbose but also easier to read and understand. Especially when it comes to complex css values where nobody really knows the order of those things. |
React 15 has no way to handle fallback CSS values (for example, vendor prefixed 'display:flex' values) in inline styles. This patch drops all fallback values for inline styles at the cost of regressing browser support (those without standard flexbox support will not layout React Native components correctly). Fix #131
So what is the status here? This is really a huge issue for everyone who is using inline-styles. Any help needed? |
We don't have enough agreement on the "multi" approach to move forward on it. It's probably not worth the complexity. Setting styles always as an attribute is possible but serializing everything to strings is not the direction we want to move in the long term so it would probably be better to find a way to fix the subtle bugs while retaining the strategy of setting individual properties only when necessary. |
Thanks for your response. Maybe there is problem that two issues are mixed up here:
I agree that there might be a better solution for the subtle bugs as in the fiddle above. But for vendor prefixing I don’t see any other option then setting styles as an attribute. Obviously we can’t assign multiple values to So maybe it’s worth splitting these two issues. Sorry for focusing on the second one, I’m having a lot of pain with this. |
Thank you for your pull request. We require contributors to sign our Contributor License Agreement, and yours has expired. Before we can review or merge your code, we need you to email cla@fb.com with your details so we can update your status. |
@spicyj No news in nearly a year. Was any consensus achieved? Is there anything actionable, or should this be closed? Otherwise, I'm thinking about closing this out. What do you think, @aweary? How do we usually handle long out of date PRs that aren't making headway? |
please don't close. It's the last mile in inline-styling. |
I'm going to close this because it's unlikely we'll merge this exact code. It doesn't mean we won't fix the issue this is trying to fix. The current status is:
|
We have several minor/subtle issues with styles, all of which get knocked out by this PR.
For instance,
initial render
of a component should be identical to [initial render
,different render
,initial render
again]. That is, the only thing that SHOULD matter is the most recent render. However, if with our old code, there are edge cases where this is untrue (eg. when specifying a general style and a more specific style). Example: http://jsfiddle.net/0861av29/ Historically, we've told people "don't do that", but that's not a good answer. For users, the old code made it hard to solve in general, because this situation often arrises when a parent clones a child and append an additional (more specific) style. This creates complex interactions between components that are difficult to debug. Solved by this PR.Another big fix, this PR also enables vendor prefix for css values, which has been a popular request for a long time. Syntax looks like this: