React Native Quirks

Martin Adamko
codeburst
Published in
5 min readMay 1, 2017

--

Somebody should told me this before

If you want to start with CSS in the React Native and if you come from the web environment just like me, the React Native environment comes with its own set of quirks. Here is a list of some I had to face for the last few weeks.

Edit: Since I’ve written this article I found other options to tackle the quirks. Moreover, React ecosystem changes rapidly and so do the “quirks”. I’ve found out some of these thoughts were false, but I keep it here for the record though and for learning purposes from my mistakes. So look for the “Edit” sections for getting the update on the quirk.

First, the setup.

Follow the Get Started tutorial. Here’s my .~/profile contents:

#!/bin/bash
export ANDROID_HOME=${HOME}/Library/Android/sdk
export PATH=${ANDROID_HOME}/emulator:${PATH}
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/tools/bin
export PATH=${PATH}:${ANDROID_HOME}/platform-tools

Note: Extra parts are shown bold.

$ react-native init App
$ cd App
$ react-native run-ios
$ emulator @Nexus_5_API_23_x86_64
$ react-native run-android

Note: Nexus_5_API_23_x86_64 is the name of the AVD you’ve specifield. See Running emulator from the command line.

Issue #0: No mention in the official Docs how to setup custom fonts

I’ve downloaded the Open Sans from Google Fonts to set up this font to for both platforms. Here’s how I’ve added the font:

Step #1: Add to package.json:

{
...,
"rnpm": {
"assets": [
"./App/Fonts"
]
}
}

Step #2: Link fonts: react-native link.

Step #3: Use fontFamily: 'OpenSans-ExtraBold, that’s the file name without the .ttf extension. Do not use fontWeight rule if not necessary.

Note: fontFamily: 'OpenSans-Regular' does not work. Use fontFamily: 'OpenSans'

Issue #1: OSes render line height differently

When setting the lineHeight, the origin of the line is at the base line on Android, on iOS it origins at the cap height. Therefore Android trims descenders (like p, q or y), iOS trims ascenders (diacritics).

Edit: I wrote another article about adjusting the font files rather than hacking with paddings. Do not apply any of this section and read the linked article instead.

Note: Here’s quick reminder about what is what in the typography.

Workaround: Always set the line height explicitly, mix paddingTop for iOS, paddingBottom for Android, try setting the includeFontPadding: false. Values are matter of trial/error to get proper results. (I’ve overlaid image in the photoshop and counted pixels.)

Example:

import {Platform, StyleSheet} from 'react-native'export default StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
lettersRow: {
flexDirection: 'row'
},
letters: {
backgroundColor: '#66CCFF',
color: 'blue',
fontFamily: 'OpenSans-ExtraBold',
fontSize: 100,
includeFontPadding: false,
lineHeight: 100,
margin: 10,
paddingBottom: Platform.OS === 'ios' ? 0 : 28,
paddingTop: Platform.OS === 'ios' ? 28 : 0,
textAlign: 'center',
textAlignVertical: 'center'
}
})

Note: textAlignVertical: ‘center’ has a minor impact on rendering, mainly for the line heights above the default line height.

Note: iOS nor Android aproaches setting the lineHeight ideally. On the web the line height is distributed more or less evenly above and below.

Note 2: I’ll do some more research to come up with a lambda to use to set up the font styles, so stay tuned.

Issue #2: Flexbox has issues with long text and Image in a row

Look at the image closely you’ll notice how the inner <Text /> is rendered the same with or without the image. As if the <Image was not taken into account when calculating the row layout.

Note: First I also thought the flexbox layout is having issues with ‘space-between’.

Edit: There should be no need to change the structure. Try it without wrappers first. Add flexShrink: 1 or flex: 0.999 on the <Text /> node. That should work fine.

Ideal structure:

<View style={styles.row}>
<Text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</Text>
<Image source={require('./assets/images/Icon.png')} />
</View>

Workaround:

<View style={{flexDirection: 'row'}}>
<View style={styles.row}>
<Text style={{flex: 0.999}}>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</Text>
<Image source={require('./assets/images/Icon.png')} />
</View>
</View>

So wrap the row in another row and add {flex: 0.999} to the <Text /> element.

Issue #3: Android prefers whole numbers for setting the font dimensions

Solution: Wrap calculations in the Math.ceil() to fix rounding issues.

Issue#4: Animation component doubles the margins

(Not sure how to replicate this issue isolated right now. Might be related to the custom component’s erroneous passing of props (the style) to the children.)

[GIF] Various stages of inspecting the card margins/backgroundColor issue on Animation wrapper and its child component.

In my case the component applied double margins: on the Animated container and also on its children. Background colour was inherited on the children too. Other CSS rules have been have been inherited automatically too without the side effects.

Edit: I honestly think this was a rookie mistake caused by me and myself only. So be careful when using spread and style later like this <View {...this.props}><View styles={this.props.style} /></View>. Style gets therefor applied twice using {...this.props} and later using this.props.style without you being fully aware of it. Use props explicitly or make sure you know what {...this.props} does.

Possible workaround: explicitly set margins, backgroundColor or/and wrap children in <View />.

Issue #5: Android ignores negative margins

Solution: Try to recreate the design with the positive margins. Position: relative with negative units do work though.

Note: Since margins do not collapse at all, possibly the best way to tackle this is to use halve margins from the start as a styling strategy.

Edit: This is not entirely true, Android can do negative margins but since they have some odds recreate the design with positive margins whenever possible.

Issue #6: it’s hard to select elements in the Android Inspector

Solution: Add temporary padding to the element or its container and inspect it. Click around. Repeat until success.

Edit: Install the ReactDevtools app. You’ll gain access to the full DOM tree, edit styles and lots of goodies.

Issue #7: Android ignores box shadow

Solution: Use {elevation: n}, where n is a whole number from 1 to 24. Ideally use [1, 2, 4, 6, 8, 9, 12, 16, 24] according to Material Design Guidlines: Elevation & Shadows.

Edit: Keep in mind that shadows on Android require parent element to have padding to render shadow. Otherwise the shadows gets clipped.

Issue #8: Android uses a default grey text colour; iOS uses full black

Solution: Always explicitly define the text colour.

Let me know if you ♥︎ the article in the comments. Thanks for stopping by!

--

--

One that loves design, illustration, photography, digs in code, adores his dog and enjoys life & good coffee. http://be.net/martin_adamko