React-native-web: flexBasis: 0% breaks things badly in Chrome

Created on 2 Mar 2019  Â·  28Comments  Â·  Source: necolas/react-native-web

The problem
By default flexBasis: 0% is set on all views. This forces all views to collapse to zero width or height, ignoring the content width and height.

How to reproduce
Simplified test case: https://codesandbox.io/s/w7qpz1qk75

Steps to reproduce:

  1. Create any view with flexDirection: 'row', and add children that also have flexDirection: 'row'
  2. Add "Text" (or any other self-sizing content) to the children 'row' containers

Expected behavior
Size of parent containers should be auto-calculated based on content size

Environment (include versions). Did this work in previous versions?

  • React Native for Web (version): 0.10.0
  • React (version): 16.7.0
  • Browser: Google Chrome, Version 72.0.3626.119 (Official Build) (64-bit)

You can see attached images of before (flexBasis: 0%) and after (flexBasis: auto)

before

after

Most helpful comment

This is my tmp workaround:

flexBasis: Platform.OS === 'web' ? 'auto' : '0%'

All 28 comments

Look through the commit history / issues to understand the context

Okay, I see what you are getting at from your comment in the code @necolas, but the current behavior of collapsing doesn't match RN. Let me do some more investigation and see if I can come up with a better work-around

Okay @necolas, I did more playing around and I found that:

  1. Keeping a flexBasis: auto on everything EXCEPT a style that has a flex set (to something other than falsy). Works and has the expected outcome
  2. On any style that has a flex set, flexBasis must be set to 0%
  3. This also only works if any style with a flex set also has the minWidth and minHeight set to auto

In short:

Default is: flex: 0 0 auto
IF flex is set to anything (i.e. a positive number), than flexBasis (if not set), must be set to 0%, and minWidth and minHeight must also be set to auto

This change fixes the sizing issue you are referring to across all browsers I tested (Chrome, Opera, Firefox, and Edge)

See here (some constants set directly in this one): https://codesandbox.io/s/v8q2p0jxv0

I'd like to include some layout examples to check against browsers and have a reference for any regressions in this area. The codesandbox is too complicated for me to follow or easily decompose into straight-forward layouts that I can validate against RN rendering.

How do you propose we do this @necolas ?

What if you made a codesandbox with static examples of all the cases that are "broken" with RNW 0.10? Just examples that are broken and don't match the rendering in snack.expo.io. Then I can confirm that your patch matches the RN rendering across all the browsers.

(It's worth mentioning that Yoga's implementation of flexBasis is not correct, and not all browsers interpret flexBasis the same way either. But getting the common cases close enough seems good enough until we can patch Yoga)

Alright, I can do that. I will post back when this is ready

Okay @necolas let me know if this works for you: https://codesandbox.io/s/4zxxr858z0

@necolas One thing I noticed while making this test sandbox is that part of the issue I am facing is that the internal style engine of react-native-web has no if (!styleSet) setStyle; checks, making it impossible to actually override the default of the view. One possible improvement if you don't think this "fix" is appropriate (or too dangerous from an impact perspective) might be just to add the conditional checks. If the user has already set a specified style prop, shouldn't it be honored? This would allow me (and anyone else) to choose to accept the flexBasis: "auto" behavior being slightly different across platforms, instead of having zero control over the flex sizing.

I was hoping for simple static examples that I can run on React Native too. It will take me longer to get around to look at this and evaluate the options

Static? Not sure what you mean. I had it in a more "static" way, but it went off the screen with the different examples between columns and rows. Is that what you want, and just place the whole thing in a ScrollView?

Simple layout examples that don't have scripting / toggles woven into the code, please. And something that is valid React Native code.

Alright, so I can dump all the examples into a ScrollView. What do you mean by "valid React Native" code? What about this isn't valid React Native? Do you mean an entire example React Native app?

What do you mean by "valid React Native" code?

The examples should run in snack.expo.io and not have console errors

@necolas Alright, here: https://snack.expo.io/@th317erd/fix-view-styles-react-native-web

And here: https://codesandbox.io/s/5vwzrn445n

OK thanks, still isn't what I asked for…

Simple layout examples that don't have scripting / toggles woven into the code, please

…but I can extract something from this

The "fixes" version definitely look closer to RN rendering but still not quite the same for all examples.

Yeah, I think this must related to the bugs you were speaking of in the yoga layout engine. I tried my best to exactly match RN to web, but I wasn't ever able to get it exact. Still, it is better and less broken for the browser.

Keeping the default flexBasis as auto seems to be all that is needed to "fix" these examples. https://codesandbox.io/s/wq71n3w987

What are examples where flexBasis needs to be 0% and minWidth/minHeight need to be auto?

flexBasis: '0%' is needed to more closely match RN when flex: 1 (or any number that isn't 0) is set. Basically if flex is set, flexBasis: '0%' is needed, and minWidth and minHeight need to be auto.

I don't see an example where that appears to be true

HHhmmm, good point @necolas. I wrote this example so many times I no longer remember why I did that, but I think it was because I was dealing with the default styles already set with react-native-web internally. Here is a new sandbox that is more explicit: https://codesandbox.io/s/xlq3x4mopq

Hi, what's the status of this issue / PR? It's breaking things badly as described and I need to know if I have to start a workaround task or can wait for this to be merged in (I hope the latter)

@mschipperheyn I stopped trying to assist with this project. There is no "good" work-around that I know of. You can always diff my changes on my fork and apply them yourself, or you could fork my fork and continue to work with @necolas to figure this out.

@th317erd ok, thanks for the update

This is my tmp workaround:

flexBasis: Platform.OS === 'web' ? 'auto' : '0%'

This might relate to IE11 issues (yeah, I know) where Views are invisible. I solved these by switching from flex: 1 to flexGrow: 1

After updating the whole app to basically flexGrow everywhere to fix Internet Explorer 11 compatibility last year, I tested that flex resolvedStyle.flexBasis = 'auto' fixes this too:

https://github.com/necolas/react-native-web/blob/be5106f5d3d38bc35ec8f1f802a02603416ccd99/packages/react-native-web/src/exports/StyleSheet/createReactDOMStyle.js#L109-L113

In my App I could not see any visual changes (yet). Without this, "some" views have an height of 0px in IE 11.

@necolas What is the reasoning behind 0%? Is that just a bad default or was there a good reason for it?

Super hacky test code incoming as an webpack entrypoint:

const createReactDOMStyle = require('react-native-web/dist/exports/StyleSheet/createReactDOMStyle.js')

const original = createReactDOMStyle.default
createReactDOMStyle.default = style => {
  const resolved = original(style)
  if (resolved.flexBasis === '0%') {
    resolved.flexBasis = 'auto'
  }
  return resolved
}

(I will show myself out)

Was this page helpful?
0 / 5 - 0 ratings