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

[React Native] Expand supported CSS for React Native #1309

Closed
mjsisley opened this issue Nov 14, 2017 · 63 comments
Closed

[React Native] Expand supported CSS for React Native #1309

mjsisley opened this issue Nov 14, 2017 · 63 comments

Comments

@mjsisley
Copy link

I would like to start a discussion on expanding the CSS supported by styled-components/native.
Primary items of interest:

  • rem/em/viewport units
  • global syles
  • media queries
  • subset of pseudo classes

It would seem that some of this functionality could be included in css-to-react-native... further improving the convenience of writing styles for React Native components with styled-components. @jacobp100, this looks to be your domain.

It appears this has been discussed in at least a limited manner, but that was in context of a specific method of accomplishing these features and was some time ago.

Looking to precedent in styled-components

Based on the inclusion of shortand and convenient syntax for properties like transform, it seems that styled-components is not limiting itself to simple mapping of styles to RN. (https://www.styled-components.com/docs/basics#react-native)

Looking elsewhere in the React Native ecosystem

Addressing template questions

  • How is this product-centric? By allowing usage of em/rem units, viewport units, and media queries... creating native apps in a responsive manner (so they look ideal on all devices) would become much easier. Other included items improve convenience as well.

  • How does it make workarounds straight forward? Any functionality that is included eliminates the need for using helper libraries or each app having their own method to deal with responsiveness of their styles.

Limitations of React Native in regards to styling.

As discussed here: #1243, some css properties (such as text-transform) aren't going to be easy to support, as limitations in React Native prevent them. This discussion is meant for CSS that can be supported (as evidenced elsewhere in the React Native ecosystem) with the current state of React Native.

Related issues

@jacobp100
Copy link
Contributor

Cool! css-to-react-native would only be relevant for units - the rest would have to be handled elsewhere (since we only take style declarations).

In theory, we can support rem, since it's just a multiple of 14px on iOS (and I think 12px on Android). Definitely happy to consider a PR for that.

em and viewport units could be parsed, but we would need to be pass base values to be used for them. em has additional complexity, as it depends on inheritance.

It's worth noting that if we did include these units, we could lose the (future?) ability for pre-parsing on native.

@mjsisley
Copy link
Author

I should first say thanks for your work on this @jacobp100! It's great to have the ability to use styled-components when building for native!

Some responses:

Cool! css-to-react-native would only be relevant for units - the rest would have to be handled elsewhere (since we only take style declarations).

My apologies for not digging deeper on css-to-react-native first.

I'm just spitballing here, but if features requiring css rules were to be brought to styled-components, maybe it would make sense to move the repo that is currently css-to-react-native to move css-to-react-native-style-declarations or maybe even @css-to-react-native/style-declarations, and have a new project title css-to-react-native that depends on the style declarations only repo (and maybe another rule declarations repo). Perhaps there is a better structure though or reasons not to do this.

This would allow other parts of css to be supported in the css-to-xxx part of the architecture.

In theory, we can support rem, since it's just a multiple of 14px on iOS (and I think 12px on Android). Definitely happy to consider a PR for that.

This would depend on a Platform check, correct? Which could also potentially impact pre-parsing? Or perhaps pre-parsing would be done on a per-platform basis that would make this work fine.

em and viewport units could be parsed, but we would need to be pass base values to be used for them. em has additional complexity, as it depends on inheritance.

It's worth noting that if we did include these units, we could lose the (future?) ability for pre-parsing on native.

Yeah, the base values would rely on Dimensions that would be received at runtime.

I'm not completely clear on future plans for pre-parsing on native. I suppose this would be a tradeoff. Perhaps pre-parsing could be done elsewhere and style declarations that involve these units could be left dynamic (or default base values could be used for pre-parsing, but updated at runtime).

Also, I know styled-components is avoiding config as much as possible, but perhaps using these units could be opt-in via config. Or if config is to be avoided, it could be noted in the docs that using these units would prevent pre-parsing of styles.

@mjsisley mjsisley changed the title [React-Native] Expand supported CSS for React-Native [React Native] Expand supported CSS for React Native Nov 14, 2017
@kitten
Copy link
Member

kitten commented Nov 14, 2017

@mjsisley @jacobp100 Whatever you end up going with, it'd be great to take ISTF into account, since in the foreseeable future it's likely that styled-components will move to a pipeline that's based on it: https://github.com/cssinjs/istf-spec

This would actually be great for a lot of RN transformations, since a lot of transformations can be done just once using the ISTF format.

@mjsisley
Copy link
Author

ISTF looks great! What is the current target for the ISTF pipeline? v3?

It makes sense to wait for the ISTF spec to be finalized and an implementation brought to styled-components before doing much on this front.

Based on this, the task would become expanding supported ISTF for React Native (and something like ISTF-to-react-native would be used)?

styled-components/native CSS-> ISTF -> react-native stylesheet

@kitten
Copy link
Member

kitten commented Nov 16, 2017

@mjsisley I'd leave that in @jacobp100's judgement 😄 It'll certainly still take a while for this pipeline to be completed.

Since ISTF is just a format our idea is to introduce transformers, like for ASTs as in Babel, to introduce certain features and changes. So we'd just need to transform ISTF as we transform CSS today, and on top of that we should have the ability to support lots of new features with less effort.

@sebasgarcep
Copy link

Would it be too hard to introduce at least media queries?

This is basically the only thing stopping us from using styled components everywhere.

@kitten
Copy link
Member

kitten commented Dec 31, 2017

@sebasgarcep this would be a great starting point for a library that adds helpers for media queries. On Native it could just use the Dimensions window API.

I could write a quick proof of concept if you’d like? That has been on my todo list for a while. If you’re interested it’d be great to maintain a community wide version on the org

Edit: actually, I could add native support to @morajabi’s https://github.com/morajabi/styled-media-query

@sebasgarcep
Copy link

sebasgarcep commented Dec 31, 2017

@philpl Skimming through the source of styled-media-query I've noticed it depends on styled-components css method for parsing media queries. So I don't think that last suggestion is going to work unless you have something else in mind.

And I tried to understand the source of styled-components but can't wrap my head around how it works, so if you can get something working it would be really nice 😄

@corysimmons
Copy link

Please beef up support for RN including things like media queries, or put a big banner at top of this page that says you don't support things like media queries.

Who makes RN apps w/o media queries? 😤

@zomars
Copy link

zomars commented Mar 20, 2018

Why this is not a thing yet?

@morajabi
Copy link
Member

@sebasgarcep

So I don't think that last suggestion is going to work unless you have something else in mind.

Actually, @kitten meant we can add media queries support for RN by mixing Dimensions window API with styled-media-query to make it work there as well :)

@micimize
Copy link

micimize commented May 7, 2018

@jacobp100 I think the reasons for rejecting #489 should be reconsidered. The reasons given, as far as I can tell:
1. hesitance to take on more/incorrect dependencies
2. the consideration of a more general solution in #504
3. "nobody has asked for this feature"

2 got shot down and 3 is clearly no longer the case, so that just leaves 1. I don't see why leveraging external libraries today means we can't replace them later, either with internal implementations or other libraries. If adding extended-stylesheet support is still even close to as simple as 489 makes it look, we could really have most of this functionality by tomorrow.

@rxb
Copy link

rxb commented Jun 25, 2018

Good to see this discussion is still alive in an open issue!

This would be hugely helpful for styled-components primitives. If someone uses media queries to handle responsiveness on the web, it's difficult to have to take a pure js strategy on native if the components and styles are shared.

@jacobp100
Copy link
Contributor

@kristerkari has a project that supports additional units. As for media queries, I got something working in cssta.

Probably the biggest issue is that these both require adding a runtime to the components, and styled-components doesn't have anything like this yet. There'll probably be a lot of bikeshedding around that

@kristerkari
Copy link

kristerkari commented Jun 26, 2018

Yeah so my project react-native-css-modules has support for rem/viewport units and CSS media queries by using regular CSS files.

Adding support for em units is probably too complicated and not worth it.

With rem units I decided to just default to use 16px for the root element font size (for Web compatibility), which is of course not always optimal, because on the Web you can easily change that value to be something else.

For media queries and viewport units I have created library that calculates the values at runtime based on the values from React Natives Dimensions API.

Here's a simplified example of how I parse/match the media queries:
https://github.com/kristerkari/react-native-css-media-query-processor#example

I think that the same things that I have implemented can be implemented styled-components, but there just needs to be some libraries to handle the runtime calculations.

I'm willing to help out with figuring out things, or even creating common libraries as my own project, cssta and styled-components have similar goals.

@rxb
Copy link

rxb commented Jun 29, 2018

The fantasy version of this for me would be to keep styled-component's use of css media queries on web and then do what you've outlined for native. Other libraries have gone 100% JS dimension-detecting on both web and native in an effort to have support on both platforms -- which works unless you want to be able to server side render your pages (the server will never know the dimensions of the screen on request and will have to render styles for a default breakpoint)

@henrymoulton
Copy link

@mjsisley I'm on a project now where we're assessing options for using responsive units with React Native and Styled Components, is there a work around for achieving this yet?

React Native Extended Stylesheet is now a pretty popular library: https://www.npmtrends.com/react-native-extended-stylesheet

@henrymoulton
Copy link

Looks like #489 was closed a few years ago, is there a chance it would be merged into the project today?

@jacobp100
Copy link
Contributor

Nothing has changed on this front since then, so that PR is still unlikely to be merged

@henrymoulton
Copy link

henrymoulton commented Jun 26, 2019

I think what's changed in the last 2/3 years for React Native developers is that they recognise that some scaling is required across device sizes - React Native Extended Stylesheet's increased download count might support this claim.

Having a way to achieve this inside of Styled Components would be ideal.

@kristerkari
Copy link

I think what's changed in the last 2/3 years for React Native developers is that they recognise that some scaling is required across device sizes - React Native Extended Stylesheet's increased download count might support this claim.

Having a way to achieve this inside of Styled Components would be ideal.

Looking at the previous discussion, it seems to me that the problem is more related to the fact that the responsive CSS features require some kind of runtime library for React Native to be added on top of styled-components. It's quite difficult to just pick some of the existing libraries, because you would get more than you are asking for (a lot of features that you are not using).

Maybe there has not been anyone willing to put all the effort (probably hundreds of hours) into creating completely new libraries that would be styled-components specific.

I know that at least media queries, viewport units, transitions, animations and variables are possible to implement in React Native.

A good example of this is the cssta library:
https://jacobp100.github.io/cssta//native/animations/

@Sharcoux
Copy link

Sharcoux commented Apr 3, 2020

I think I might be able to make a PR for this. I'm just a little lost with the project structure. Can anyone help me out? I'll explain what I intend to do.

vw, vh

This is the easiest part I think.
There should be a moment in the process where the styled string was computed and is going to be parsed into a style object. For what I understand, it happens here.

For vw support for instance, we could add a step where we read values for '([0-9]+(\.[0-9]+)?)vw'. If we find such a value, we parse the first capture groupe into a number and calculate number * Dimensions.get('window').width / 100. We then replace the original value with the calculated one, and we replace the unit with px.

em

For this, it becomes quite easy with the Context API. But we need to assume that all the font-size styling uses styled-components. I think that it is fair to request as much from the users if they want to use em units.

Then, all we have to do is create a FontSizeContext initialized to 16, and each time we encounter the style key "font-size", we create a new context Provider with the calculated value within. And each time we encounter an 'em' value, we create a context Consumer to read the current font-size value within the DOM tree, and deduce the actual value of the props.

Can someone who is familiar to the project help me out on where I should introduce this logic?

@jacobp100
Copy link
Contributor

@Sharcoux I'm not too familiar with the SC project, but I think you're on the right lines for vw/vh. You'd have to do some refactoring because you'll need to listen to dimension changes for when you change from portrait to landscape - and you'd only want to listen to those changes if the component actually depended on these units

@Sharcoux
Copy link

Sharcoux commented Apr 3, 2020

Nice remark. I think I'm set up. I understood where to put my code I think. I'm on my way to create a first draft.

@Sharcoux
Copy link

Sharcoux commented Apr 3, 2020

@jacobp100 @kristerkari could you check what I did if you have a few minutes? I'm still having some minor issues to fix. In the meantime, i'll give it a try for the em system as I couldn't test it with the testing API in place.

@jacobp100
Copy link
Contributor

I did a brief review - but neither of us actually work on the styled-components project. We develop css-to-react-native for our own projects and share the library with styled-components

@Sharcoux
Copy link

Sharcoux commented Apr 4, 2020

Ok, Technically, I'm done. I Had to make some architectural choices that might be not ideal in terms of readability but that I can defend in terms of performance.
My last issue is flow. Can someone help me fix that?

@Sharcoux
Copy link

Sharcoux commented Apr 7, 2020

But I need to listen to the screen size BEFORE calling css-to-rn, same for em if I want to retrieve the current value...

@jacobp100
Copy link
Contributor

jacobp100 commented Apr 7, 2020

How about something like,

const Example = () => {
  const forceUpdate = useForceUpdate()
  const { width, height } = Dimensions.get('window')

  let didUseViewportDimensions = false
  const style = cssToReactNative([['width', '60vw']], {
    get vw() {
      didUseViewportDimensions = true
      return width / 100
    }
  })

  React.useEffect(() => {
    if (didUseViewportDimensions) {
      Dimensions.addListener(forceUpdate)
      return () => Dimensions.removeListener(forceUpdate)
    } else {
      return undefined
    }
  }, [didUseViewportDimensions, forceUpdate])

  return <WrappedComponent style={style} />
}

@Sharcoux
Copy link

Sharcoux commented Apr 7, 2020

Yeah, sorry, you are right about v-units. This would work.
About em though, the issue will be about handling the case when we edit the font size.

@jacobp100
Copy link
Contributor

That’s why I think doing it two PRs would make more sense. It will be possible to add font size support, but the overhead might be significant

@Sharcoux
Copy link

Sharcoux commented Apr 7, 2020

Hum... But to create the PR for v-units, it means that I would need to wait for you guys to provide the API that you described above... Do you see a valid reason to do this whereas we can have it working right now?

@jacobp100
Copy link
Contributor

I’m not a maintainer for styled components, I just know a bit about parsing css and giving my 2c. It’s up to the maintainers what happens in their project

I do think this approach effectively adds css parsing though another means, which is a huge undertaking. We have a huge test suite for each property shorthand supported and we’ve referred to the css specification for these tests. Also, I think properties like border-left-width, border-top-right-radius might be broken in your PR

We would consider a PR in css-to-react-native for something that adds the ability to resolve these units though

Hope this helps! 😃

@Sharcoux
Copy link

Sharcoux commented Apr 7, 2020

I don't think that border-left-width and border-top-right-radius would be broken. They should enter the last case where we just read and strip the unit and mark borderLeftWidth and borderTopRightRadius for update after receiving css-to-rn result. Is there something I'm missing?
I can add a test if needed.

@kristerkari
Copy link

kristerkari commented Apr 8, 2020

Thinking about it, it might actually be possible for us to add partial support in css-to-react-native if you pass in an object of values for dimensions (like what 1rem is equal to). We could probably also tell you what units were used

Yeah we could totally do that, if it means that we can still support my use case with viewport units which is to parse the CSS at bundle time and do the viewport unit calculations at runtime.

I previously created this small library for my own use to do the viewport units calculation:
https://github.com/kristerkari/css-viewport-units-transform

@jacobp100
Copy link
Contributor

@kristerkari It would definitely support doing it at runtime. It looks like we'd just have css-to-react-native absorb your css-viewport-units-transform. Does that work for you?

@kristerkari
Copy link

It looks like we'd just have css-to-react-native absorb your css-viewport-units-transform. Does that work for you?

Sure, that's fine.

@Sharcoux
Copy link

Sharcoux commented Apr 8, 2020

It would still remain the problem for the user to know if it should listen to window's size changes...

@jacobp100
Copy link
Contributor

The example I gave above (using getters) should give you that information. We can look at adding a more official API later

@Sharcoux
Copy link

Sharcoux commented Apr 8, 2020

My bad, I misunderstood how you imagined this being used. Indeed, that would work.

@Sharcoux
Copy link

Sharcoux commented Apr 9, 2020

So what's up guys. @jacobp100 @kristerkari , should I be doing something?

@jacobp100
Copy link
Contributor

I don't have a tonne of time at the moment to do this, but I can review a PR if you wanted to give it a shot. Or if I get some time I can pick it up later, but I don't know when that will be

@Sharcoux
Copy link

Sharcoux commented Apr 9, 2020

Well... I tried to understand how things worked there, but I'm not quite sure, so I'd rather let you do it, sorry...

@kristerkari
Copy link

kristerkari commented Apr 10, 2020

I'm not very familiar with styled-components' codebase, but I can have a look at the PR.

@Sharcoux
Copy link

Hi all. So what should we do about this?

@Sharcoux
Copy link

Guys, I don't understand. This seems to be a feature requested for a long time. I'm sure that the current implementation in this PR does fill the gap. Isn't there anyone working for this project that could help finishing it? The only issue remaining comes from the tools that were chosen for the project (flow, mainly)...

@Sharcoux
Copy link

Basically, I created rn-css to fix this issue. I'm also bringing other stuff like hover. It's not yet ready for production because of some performance issues I need to fix, but I'm close. I'll also bring media queries. For people looking for a solution while this subject is being merged into styled-components, you can give it a try.

@robertwt7
Copy link

Hey Guys,

Sorry to brought it up. But what's the update on this? I'm trying to use react native on the new project (coming from react and styled-components) but it seems like there are some units missing. I can't seem to find the conclusion after reading the docs and comments here.

Does the css-to-react-native allows us to use em and rem in react native now?

Cheers

@Sharcoux
Copy link

I'd say that the solution for now is to use rn-css in the place of styled-components (just replace all occurences of styled-components/native by rn-css within your project). I just advice you to update it every week as there are some performance issues that needs to be fixed.

@Sharcoux
Copy link

Sharcoux commented Jun 1, 2020

Well, for those interested, I think that rn-css is now working as expected. Please report if you have issue.
I strongly believe that having a project dedicated to RN specificities will be better in the long run than the hybrid approach of styled-components. There are pros and cons of course, but I'm affraid that the hybrid approach will raise limitations.

@calumjames
Copy link

I'd say that the solution for now is to use rn-css in the place of styled-components (just replace all occurences of styled-components/native by rn-css within your project). I just advice you to update it every week as there are some performance issues that needs to be fixed.

@Sharcoux, looking at the documentation of rn-css, things like first-child, nth-child etc. can't be used. Is that correct?

@Sharcoux
Copy link

Sharcoux commented Jul 13, 2020

@calumjames, this feature would request or to have a ref to the parent which seems complicated to obtain, or to ask users that parents of such a feature must be created with rn-css, which seems more likely to introduce bugs than to help the user.

On the other hand, just passing the index of the child as a props and using this kind of code within your component seems easy enough:

const StyledChild = styled(Child)`
  ${props => (props.index % 2) ? /* your css if index is not multiple of 2 */ : /* your css if index is multiple of 2 */}
`

You could even create a HOC like that to automatically inject the index as props to your children:

const withIndex = (Component) => ({children, ...props}) => {
  return <Component {...props}>
    {
      React.Children.map(children, (child, index) => React.cloneElement(child, { index }));
    }
  </Component>
}

(I didn't exactly try the above code, so use with care)

@calumjames
Copy link

Thanks for the response, @Sharcoux. I went with the index idea in the end, so it's good to see that's probably the best way for now.

@lucassm02
Copy link

Try using this library emotion-native-extended, also advise, look at this publication.

@kitten
Copy link
Member

kitten commented Aug 9, 2021

We likely would only address this if we start working on #1617. Closing due to inactivity.

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

Successfully merging a pull request may close this issue.