-
Notifications
You must be signed in to change notification settings - Fork 47.6k
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
Allow style object to accept array of values #723
Conversation
@brainkim Is this actually useful for anything besides However, it seems like vendor prefixes overall may need considering for React. Edit: Hmm, this is actually useful for CSS3 backgrounds too. |
Off the top of my head there's also background: linear-gradient and fallback CSS3 colors (hex, rgb, rgba).
|
What about things like |
@benjamn Grah! I hadn't thought of that. That could be surprising behavior. As it currently stands though, you would do On Fri, Dec 27, 2013 at 9:18 AM, Ben Newman [email protected]:
|
Yeah the |
I feel like those use cases can easily be addressed by a small wrapper that has feature detection.
But, if you really need to write them using fallback, you can just make a CSS rule for them and add use a class. |
Regarding vendor prefixing: we talked about doing vendor prefixing in React a while ago but decided it was a lot of bytes and complexity for little payout. |
@vjeux I like this suggestion. I just looked it up and @petehunt I agree. Who actually wants to keep track of vendor prefixes? |
Problem with vendor-prefixes is also that some of the time they are just that because they aren't 100% compatible. Given proper |
Maybe we should modify the react/src/core/ReactDOMComponent.js Lines 57 to 61 in d914522
|
@syranide I don't understand your argument. The only reason vendor prefixes exist is because fallback is such a rock-solid strategy for the browser. I can't think of a single situation where using
and these fallback functions will be full of suck because we're now asking the DOM a series of questions for every render. We could always memoize the fallback function, but then the burden of evidence is on you to prove that requiring a memoized function and a browser shim whenever you want inline css fallback is better than simply setting a rule multiple times with an array. I sincerely do not know why we're not jumping at this opportunity to reduce cyclomatic complexity in our applications, except perhaps a misbegotten sense of propriety derived from archaic "best practices." The thing I like about React is that it doesn't insist that we need the holy trinity of html, css, and javascript to separate concerns, and we get a lot of cool things like react-styles as a result. I argue that the In short, this pull request embodies the very essence of React.js and the United States of America is the greatest country in the world. I'm going to go stick my head in a bucket of water. Thank you. |
@fabiomcosta I think that invariant exists because React will actually merge style objects when using var RedDiv = React.createClass({
render: function() {
return this.transferPropsTo(<div style={{backgroundColor: 'red', outline: 'black solid 1px'}}>{this.props.children}</div>);
}
} and then call it like so: React.renderComponent(<RedDiv style={{outline: 'blue dotted 1px'}}>Hello world!</RedDiv>, mountNode) the resulting div will have a style object of |
@brainkim I don't count as official opinion on React, but it seems dangerous to rely on The problem in my opinion with vendor-prefixes is that they are for a reason, either because it's based on a non-final standard, it's not based on any standard at all or because there genuinely are differences. Opacity doesn't work the same across all browsers in all cases. So by forcing use of prefixed versions we make some things easier, but we also prevent some options. As in, feature |
@syranide i need this pull request. pls. my children will starve without it. |
@brainkim As I alluded to above, I'm not part of the team. |
I understand. No worries! On Fri, Dec 27, 2013 at 5:09 PM, Andreas Svensson
|
Given that's a very broad API for a very narrow use case and there work-arounds available, I'm going to close this pull request. Thanks a lot for submitting it, it's always good to stimulate a healthy debate on the API! |
KK. Happy new year! On Tue, Dec 31, 2013 at 3:15 PM, Christopher Chedeau <
|
I'm sorry to resurrect this pull request, but I'm not sure what the available workarounds are for the specific problem I'm encountering: I'm rendering an item with a linear gradient background image that's based on the dominant colors extracted from the item's image, which means I need to specify the background image rule inline on the item (rather than, say, specifying the image in a class defined in a stylesheet). And in order for this to work across browsers, I need to specify a separate background-image: -webkit-linear-gradient(left, #900 0, #009 100%);
background-image: -moz-linear-gradient(left, #900 0, #009 100%);
background-image: linear-gradient(left, #900 0, #009 100%); What's the best way to handle this situation given the constraints around the |
@mccutchen Instead of adding all of them, detect which one is the correct and apply only that. It will be faster too. |
I think this is worth revisiting. I was reading @vjeux's React: CSS in JS, and in trying to implement it, I immediately ran into issues with flexbox (the I quickly hacked this together in diff --git a/src/browser/ui/dom/CSSPropertyOperations.js b/src/browser/ui/dom/CSSPropertyOperations.js
index 3417378d..900fc699 100644
--- a/src/browser/ui/dom/CSSPropertyOperations.js
+++ b/src/browser/ui/dom/CSSPropertyOperations.js
@@ -78,10 +78,15 @@ var CSSPropertyOperations = {
warnHyphenatedStyleName(styleName);
}
}
- var styleValue = styles[styleName];
- if (styleValue != null) {
- serialized += processStyleName(styleName) + ':';
- serialized += dangerousStyleValue(styleName, styleValue) + ';';
+ var styleValues = styles[styleName];
+ if (styleValues != null) {
+ if (!Array.isArray(styleValues)) {
+ styleValues = [styleValues];
+ }
+ for (var i = 0; i < styleValues.length; i++) {
+ serialized += processStyleName(styleName) + ':';
+ serialized += dangerousStyleValue(styleName, styleValues[i]) + ';';
+ }
}
}
return serialized || null;
@@ -105,22 +110,28 @@ var CSSPropertyOperations = {
warnHyphenatedStyleName(styleName);
}
}
- var styleValue = dangerousStyleValue(styleName, styles[styleName]);
if (styleName === 'float') {
styleName = styleFloatAccessor;
}
- if (styleValue) {
- style[styleName] = styleValue;
- } else {
- var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
- if (expansion) {
- // Shorthand property that IE8 won't like unsetting, so unset each
- // component to placate it
- for (var individualStyleName in expansion) {
- style[individualStyleName] = '';
- }
+ var styleValues = styles[styleName];
+ if (!Array.isArray(styleValues)) {
+ styleValues = [styleValues];
+ }
+ for (var i = 0; i < styleValues.length; i++) {
+ var styleValue = dangerousStyleValue(styleName, styleValues[i]);
+ if (styleValue) {
+ style[styleName] = styleValue;
} else {
- style[styleName] = '';
+ var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+ if (expansion) {
+ // Shorthand property that IE8 won't like unsetting, so unset each
+ // component to placate it
+ for (var individualStyleName in expansion) {
+ style[individualStyleName] = '';
+ }
+ } else {
+ style[styleName] = '';
+ }
}
}
} (This can be optimized a bit so you don't create arrays for every prop.) I don't think React should be in the business of determining what is/isn't a valid prefix - but it should respect wanting to set different values for the same css property. I'm not going to defend the sanity of this, but it is undeniably a pattern that's widely followed in the webdev community. To get a feel for what properties someone might want to do this for, just look at autoprefixer. Look for the classes that extend UPDATE: lol hadn't looked at the PR's code since it was so old - just quickly looked at the comments - hooray for reinventing the wheel! |
I don't understand why this pull request was closed, as it fixes an actual problem with inline styles. This would make inline styles more flexible. Anyway, anyone trying to inline-style a gradient or something similar, here's a very hacky workaround that works (without you needing to check for available features as syranide suggested) var style = {
background: "linear-gradient(to right, #5c8484 0%,#ea4f07 100%); background: -webkit-linear-gradient(left, #5c8484 0%,#ea4f07 100%)"
}; So just:
|
For gradients, you can just use a helper like this: 'use strict';
var GRADIENT_VARIANTS = {
'LinearGradient': 'linear-gradient',
'WebkitLinearGradient': '-webkit-linear-gradient',
'WebkitGradient': '-webkit-gradient',
'MozLinearGradient': '-moz-linear-gradient',
'msLinearGradient': '-ms-linear-gradient'
};
var test = function (topColor, bottomColor) {
var testEl = document.createElement('div'),
style = testEl.style;
for (var gradientName in GRADIENT_VARIANTS) {
var prefixedString = GRADIENT_VARIANTS[gradientName],
gradient = '',
templateString = '';
style.backgroundImage = '';
if (gradientName === 'LinearGradient') {
gradient = prefixedString + '(to bottom,' + topColor + ',' + bottomColor + ')';
templateString = prefixedString + '(to bottom, %topColor%, %bottomColor%)';
} else if (gradientName === 'WebkitGradient') {
gradient = prefixedString + '(linear,' + topColor + ',' + bottomColor + ')';
templateString = prefixedString + '(linear, %topColor%, %bottomColor%)';
} else {
gradient = prefixedString + '(top,' + topColor + ',' + bottomColor + ')';
templateString = prefixedString + '(top, %topColor%, %bottomColor%)';
}
style.backgroundImage = gradient;
if (style.backgroundImage.length) {
test.templateString = templateString;
return gradient;
}
}
};
var gradient = function (topColor, bottomColor) {
if (!test.templateString) {
test(topColor, bottomColor);
}
return test.templateString.replace('%topColor%', topColor).replace('%bottomColor%', bottomColor);
};
module.exports = gradient; It's not very flexible (just top to bottom) but you can modify it as you see fit.. |
Over a year ago @vjeux closed this because it was a
The main work around advocated was to dynamically add only the relevant prefix in the browser. With the rising popularity of inline styles and isomorphic apps, this workaround doesn't cut it anymore. You can't only dynamically prefix in the browser, since that will cause an inconsistency between the server and client rendered HTML, which breaks isomorphism. For example, it's needed in the biggest(?) library of components: mui/material-ui#748 #popitopen |
Has history vindicated me yet? 😛 |
What's the best way to prevent invalid checksum errors on a universal app when a third-party component is doing browser detection? Fallbacks are used in the browser, but not on the server. The only option I see is to fork the component and extract styles into a stylesheet. |
This allows components to set multiple values for a single css rule. The main use case is to set vendor prefix styles and allow for broader css compatibility. Example:
When the component initially renders, all styles will be set through the inline markup string. When the component updates its style, the last valid style in the array will be set.
This change does not handle the edge case where you pass in a singleton array of an empty string, in the sense that it improperly unsets shorthand rules in IE8. I think the css stuff is due for a refactoring anyways though.
Something to think about: Should react manage css vendor prefixes automatically?
Other things I did:
CSSPropertyOperations.setValueForStyles
Edit: Added backgroundColor to example.