facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.97k stars 24.31k forks source link

Text rendering is inconsistent on ios and android #32384

Closed pvinis closed 3 weeks ago

pvinis commented 3 years ago

Description

It seems that with the same style, Text on Android renders higher than on iOS, and that could cause problems wherever text is involved, especially vertically centered text.

React Native version:

npx react-native info
info Fetching system and libraries information...
System:
    OS: macOS 11.4
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 1.78 GB / 16.00 GB
    Shell: 5.8 - /usr/local/bin/zsh
  Binaries:
    Node: 16.10.0 - ~/.asdf/installs/nodejs/16.10.0/bin/node
    Yarn: 1.22.10 - ~/.asdf/shims/yarn
    npm: 7.24.0 - ~/.asdf/installs/nodejs/16.10.0/bin/npm
    Watchman: 2021.09.27.00 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.10.1 - /Users/pavlos/.asdf/shims/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 15.0, DriverKit 20.4, macOS 11.3, tvOS 15.0, watchOS 8.0
    Android SDK:
      API Levels: 26, 29, 30
      Build Tools: 26.0.3, 28.0.3, 29.0.2, 30.0.2, 31.0.0
      System Images: android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom
      Android NDK: 22.1.7171670
  IDEs:
    Android Studio: 4.2 AI-202.7660.26.42.7351085
    Xcode: 13.0/13A233 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_252 - /Users/pavlos/.asdf/shims/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2
    react-native: 0.66.0 => 0.66.0
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. clone https://github.com/pvinis/react-native-text-render-bug
  2. yarn && yarn start
  3. yarn android
  4. yarn ios

Expected Results

I would expect the android text to have a pixel space from the top border, same as ios.

Snack, code example, screenshot, or link to a repository:

BlueBazze commented 3 years ago

You are forgetting safe area on ios. And different screen sizes, pixel density. https://reactnative.dev/docs/height-and-width

pvinis commented 3 years ago

there is no SafeArea involved here. and yes, different sizes etc, but it is pretty obvious here that the text is too high on android.

look at the borders (which are the same). the g tail is as far from the border as much as the T is form the top border, on ios. Not the same for android, where the g is far away, and the T is touching.

This is not an issue of safearea or pixel density.

BlueBazze commented 3 years ago

From your first explanation i understood it being a matter of placement of the text relative to the screen borders. Theres no problem. You just forgot to account for the different default platform fonts. Android uses Roboto, iOS uses San Francisco

pvinis commented 3 years ago

Still not the problem. I tested with custom fonts before, but I wanted to keep it simple with system fonts, even if they are different.

Here we go, I have updated https://github.com/pvinis/react-native-text-render-bug to have https://github.com/be5invis/Iosevka, same custom font for both platforms.

Screenshot

It is clear here too, that the two platforms are not rendering consistently. android seems too high up. you can see the g again touching, and the T very close to the border, on ios. android is cutting off the tops.

BlueBazze commented 3 years ago

onLayout={event => console.log({ layout: event.nativeEvent.layout, platfrom: Platform.OS, }) }

pvinis commented 3 years ago

for ios:

"layout": {"height": 18.333328247070312, "width": 100, "x": 145, "y": 0}
"layout": {"height": 18.666671752929688, "width": 112, "x": 139, "y": 27}
"layout": {"height": 18.666671752929688, "width": 106.66665649414062, "x": 141.6666717529297, "y": 54.33333206176758}
"layout": {"height": 18.333343505859375, "width": 114.66665649414062, "x": 137.6666717529297, "y": 81.66666412353516}

for android:

"layout": {"height": 18.18181800842285, "width": 96.7272720336914, "x": 148, "y": 0}
"layout": {"height": 18.18181800842285, "width": 109.81818389892578, "x": 141.4545440673828, "y": 27.272727966308594}
"layout": {"height": 18.18181800842285, "width": 106.18181610107422, "x": 143.27272033691406, "y": 54.54545593261719}
"layout": {"height": 17.81818199157715, "width": 114.18181610107422, "x": 139.27272033691406, "y": 82.18181610107422}
github-actions[bot] commented 2 years ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

shalom-aviv commented 2 years ago

Did somebody find a solution?

steodor commented 1 year ago

@pvinis did you ever find a solution to this? Or a culprit?

pvinis commented 1 year ago

no. no idea why or how besides the investigation here. it could be the font, or it could not.

do you also get it in another font? maybe it's our chance to look into it again.

steodor commented 1 year ago

I get a similar issue using the Segoe UI font. There are a few differences but i thought maybe the issues are connected.

In our case it's not react-native but a cross-platform react app packaged (for mobile devices) in a cordova app. On web (desktop browser, no cordova) and android (cordova) the text aligns nicely with things like inline iconography and sits well vertically centered in buttons, badges or chips (e.g. tags). On iOS however, the font is rendered lower by a couple pixels and ruins everything in a lot of different contexts.

The issue seems connected as the behavior is similar (the line-height box is the same on all platforms, but iOS just renders text lower in the same box) and in the end it's still the browser (a native app) that renders it, so maybe it's the same text rendering engine?

So i just wondered if it's worth testing with different font files - if that was your solution in the end.

stefan-schweiger commented 1 year ago

It's even worse when you try to align icon fonts correctly, on iOS it more or less behaves like I would expect it, but on Android if I switch between ttf and otf the alignment changes (for the same font). Even between my physical device and the Android emulator the alignment is not 100% consistent. The Android font rendering is just a mess overall it feels like.

steodor commented 1 year ago

We have sort of identified our issue, seems to be related to a semi-bold variant of our font, which is not native but auto-generated via some tool by the design team and we have no control over that. All semi-bold texts are being rendered lower by iOS, in our case the Android mostly behaves as expected :) so yeah, quite cumbersome issues. We ended up wrapping all such texts in a custom component that we control and can do position: relative; top: -1px; on iOS only. Ugly, but it will have to do for now, and further down the road at least it's decoupled now.

stefan-schweiger commented 1 year ago

For Icons I've now gone with the solution to use a View with position: "relative", aspectRatio: 1, alignItems: 'center', justifyContent: 'center' which contains a Text with position: "absolute", includeFontPadding: false and calculate the height of the View depending on the applied fontSize of the style property... really not loving the solution but it was the only way to get the icon consistently positioned on every platform with every icon font.

fabOnReact commented 9 months ago

Do you still experience this issue?

I have four years of experience maintaining facebook/react-native and I specialize in the Text and TextInput components. I currently have 58 facebook/react-native PRs.

If you still experience this issue, I will prepare a patched release with the fix.

Thanks a lot

react-native-bot commented 1 month ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

react-native-bot commented 3 weeks ago

This issue was closed because it has been stalled for 7 days with no activity.