React Native Responsive Font Size
Asked Answered
M

17

162

I would like to ask how react native handle or do the responsive font. For example in iphone 4s i Have fontSize: 14, while in iphone 6 I have fontSize: 18.

Mithgarthr answered 10/11, 2015 at 11:13 Comment(3)
If anyone is looking for a way to completely disable font scaling, use Text.defaultProps.allowFontScaling=falseShortcoming
@Shortcoming this is brilliant!Demitria
In case you want relative fontSize based on the screen size instead of exact fontSize you can try npmjs.com/package/react-native-responsive-dimensions , It will automatically resize your fonts based on the device's screenSizeMuseum
T
160

You can use PixelRatio

For example:

var React = require('react-native');

var {StyleSheet, PixelRatio} = React;

var FONT_BACK_LABEL   = 18;

if (PixelRatio.get() <= 2) {
  FONT_BACK_LABEL = 14;
}

var styles = StyleSheet.create({
  label: {
    fontSize: FONT_BACK_LABEL
  }
});

Edit:

Another example:

import { Dimensions, Platform, PixelRatio } from 'react-native';

const {
  width: SCREEN_WIDTH,
  height: SCREEN_HEIGHT,
} = Dimensions.get('window');

// based on iphone 5s's scale
const scale = SCREEN_WIDTH / 320;

export function normalize(size) {
  const newSize = size * scale 
  if (Platform.OS === 'ios') {
    return Math.round(PixelRatio.roundToNearestPixel(newSize))
  } else {
    return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 2
  }
}

Usage:

fontSize: normalize(24)

You can go one step further by allowing sizes to be used on every <Text /> components by pre-defined sized.

Example:

const styles = {
  mini: {
    fontSize: normalize(12),
  },
  small: {
    fontSize: normalize(15),
  },
  medium: {
    fontSize: normalize(17),
  },
  large: {
    fontSize: normalize(20),
  },
  xlarge: {
    fontSize: normalize(24),
  },
};
Tryptophan answered 28/1, 2016 at 23:48 Comment(6)
where did you make use of your const scale here?Reo
This doesn't seem to do anything. mini always === 12Etom
Why are you subtracting 2 for non-ios devices?Armorial
@Tryptophan Thanks this works nicely, but why -2 on Android?Ballard
It does not work, for instance, for iPhone 12 mini and iPhone X, since they both have width 375 and pixel ratio 3. Although, obviously, the layout and font size should be aware of the difference.Bleeding
This is not the correct answer anymore. Check adjustsFontSizeToFit and numberOfLines down below.Tosha
C
82

We use a simple, straight-forward, scaling utils functions we wrote:

import { Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');

//Guideline sizes are based on standard ~5" screen mobile device
const guidelineBaseWidth = 350;
const guidelineBaseHeight = 680;

const scale = size => width / guidelineBaseWidth * size;
const verticalScale = size => height / guidelineBaseHeight * size;
const moderateScale = (size, factor = 0.5) => size + ( scale(size) - size ) * factor;

export {scale, verticalScale, moderateScale};

Saves you some time doing many ifs. You can read more about it on my blog post.


Edit: I thought it might be helpful to extract these functions to their own npm package, I also included ScaledSheet in the package, which is an automatically scaled version of StyleSheet. You can find it here: react-native-size-matters.
Cirro answered 23/3, 2017 at 8:43 Comment(4)
Thanks, what is best scenario to use this utils? I mean where to use scale, verticaleScale and moderateScale?Turnbow
I use moderateScale on almost everything that needs scaling, like fontSize, margins, image and Svg size, (for layout I use flex) because imo scaling shouldn't be linear, but that's a matter personal preference. If you'd like to achieve a linear result then use mostly scale, and use verticalScale on stuff like containers heights.Cirro
Is it ok in terms of performance to overuse it?Retrorocket
Nice code, but should you use PixelRatio or is that not necessary?Trace
C
62

adjustsFontSizeToFit and numberOfLines works for me. They adjust long email into 1 line.

<View>
  <Text
    numberOfLines={1}
    adjustsFontSizeToFit
    style={{textAlign:'center',fontSize:30}}
  >
    {this.props.email}
  </Text>
</View>
Caves answered 21/2, 2019 at 10:18 Comment(0)
M
19

Because responsive units aren't available in react-native at the moment, I would say your best bet would be to detect the screen size and then use that to infer the device type and set the fontSize conditionally.

You could write a module like:

function fontSizer (screenWidth) {
  if(screenWidth > 400){
    return 18;
  }else if(screenWidth > 250){
    return 14;
  }else { 
    return 12;
  }
}

You'll just need to look up what the default width and height are for each device. If width and height are flipped when the device changes orientation you might be able to use aspect ratio instead or just figure out the lesser of the two dimensions to figure out width.

This module or this one can help you find device dimensions or device type.

Morale answered 10/11, 2015 at 15:0 Comment(4)
i've installed the react-native-device but It gives me an error of "Unable to resolve module Dimension" when I run the appMithgarthr
Sounds like you need to make sure you are using the right version of RN for the moduleMorale
i'm using the latest version of React Native :) I think it is not currently supported?Mithgarthr
Possibly... Maybe try removing your node_modules folder and re npm installMorale
H
9

I managed to overcome this by doing the following.

  1. Pick the font size you like for the current view you have (Make sure it looks good for the current device you are using in the simulator).

  2. import { Dimensions } from 'react-native' and define the width outside of the component like so: const { width } = Dimensions.get('window')

  3. Now console.log(width) and write it down. If your good looking font size is 15 and your width is 360 for example, then take 360 and divide by 15 ( = 24). This is going to be the important value that is going to adjust to different sizes.

    Use this number in your styles object like so: textFontSize: { fontSize = width / 24 },...

Now you have a responsive fontSize.

Harmonics answered 7/9, 2017 at 11:26 Comment(4)
hey does it really works? f1 = width/ (width/size) this can't be working?Metcalfe
I ended up using react-native-text.Harmonics
c0dezer019.medium.com/thank-you-3824cb7b886c and medium.com/nerd-for-tech/… This is same as @walter plus round off etc. Thanks dude.Ophidian
Yeah my solution is not perfect but it worked in my uses cases!Harmonics
F
7

Take a look at the library I wrote: https://github.com/tachyons-css/react-native-style-tachyons

It allows you to specify a root-fontSize (rem) upon start, which you can make dependent of your PixelRatio or other device-characteristics.

Then you get styles relative to your rem, not only fontSize, but paddings etc. as well:

<Text style={[s.f5, s.pa2, s.tc]}>
     Something
</Text>

Expanation:

  • f5is always your base-fontsize
  • pa2 gives you padding relative to your base-fontsize.
Fromenty answered 3/8, 2016 at 6:59 Comment(0)
P
7
import { Dimensions } from 'react-native';

const { width, fontScale } = Dimensions.get("window");

const styles = StyleSheet.create({
    fontSize: idleFontSize / fontScale,
});

fontScale get scale as per your device.

Plasty answered 21/1, 2019 at 5:1 Comment(2)
fontscale just returns 1 on the Android Emulator 4_WVGA_Nexus_S_API virtual device I'm using.Guillermoguilloche
same for me, it always returns 1 in iOS simulatorsChenee
S
4

I simply use the ratio of the screen size, which works fine for me.

const { width, height } = Dimensions.get('window');

// Use iPhone6 as base size which is 375 x 667
const baseWidth = 375;
const baseHeight = 667;

const scaleWidth = width / baseWidth;
const scaleHeight = height / baseHeight;
const scale = Math.min(scaleWidth, scaleHeight);

export const scaledSize =
    (size) => Math.ceil((size * scale));

Test

const size = {
    small: scaledSize(25),
    oneThird: scaledSize(125),
    fullScreen: scaledSize(375),
};

console.log(size);

// iPhone 5s
{small: 22, oneThird: 107, fullScreen: 320}
// iPhone 6s
{small: 25, oneThird: 125, fullScreen: 375}
// iPhone 6s Plus
{small: 28, oneThird: 138, fullScreen: 414}
Sirois answered 17/8, 2018 at 5:36 Comment(3)
Does this mean that you have to use the iPhone 6 Simulator and based on how it looks there it will look good on other devices?Harmonics
@WalterMonecke in my case yes. You can also adapt to use other simulator as a base.Sirois
This looks good. I know its an old post, but if anyone is around, what is the logic behind the Math.min ?Oilstone
S
4

We can use flex layout and use adjustsFontSizeToFit={true} for responsive font sizes.And the text would adjust according to the size of the container.

     <Text
    adjustsFontSizeToFit
    style={styles.valueField}>{value}
    </Text>

But in styles you need to put a fontsize as well only then will adjustsFontSizeToFit work.

    valueField: {
    flex: 3,
    fontSize: 48,
    marginBottom: 5,
    color: '#00A398',
},
Selma answered 5/2, 2019 at 10:39 Comment(0)
R
3

Why not using PixelRatio.getPixelSizeForLayoutSize(/* size in dp */);, it's just the same as pd units in Android.

Reentry answered 1/3, 2019 at 20:0 Comment(0)
M
3

I'm usually using this :

import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';

var heightY = Dimensions.get("window").height;

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.textStyle}>fontSize {heightY * 0.014}</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  textStyle: {
    fontSize: heightY * 0.014,
  }
})

The idea is to get the fontSize depending on height of your screen. Example calculation:

// Height 785,.. -> fontSize = 11 
// Height 1000 -> fontSize = 14
// Height 1285,.. -> fontSize = 18

You can also try using this if you want it to depend on your screen width:

var widthX = Dimensions.get("window").width;
Meshwork answered 17/7, 2021 at 10:39 Comment(0)
B
2

I recently ran into this problem and ended up using react-native-extended-stylesheet

You can set you rem value and additional size conditions based on screen size. As per the docs:

// component
const styles = EStyleSheet.create({
  text: {
    fontSize: '1.5rem',
    marginHorizontal: '2rem'
  }
});
// app entry
let {height, width} = Dimensions.get('window');
EStyleSheet.build({
  $rem: width > 340 ? 18 : 16
});
Ballard answered 16/11, 2018 at 9:31 Comment(0)
C
1

Need to use this way I have used this one and it's working fine.

react-native-responsive-screen npm install react-native-responsive-screen --save

Just like I have a device 1080x1920

The vertical number we calculate from height **hp**
height:200
200/1920*100 = 10.41% - height:hp("10.41%")


The Horizontal number we calculate from width **wp**
width:200
200/1080*100 = 18.51% - Width:wp("18.51%")

It's working for all device

Capias answered 1/6, 2020 at 12:6 Comment(0)
V
0

A slightly different approach worked for me :-

const normalize = (size: number): number => {
  const scale = screenWidth / 320;
  const newSize = size * scale;
  let calculatedSize = Math.round(PixelRatio.roundToNearestPixel(newSize))

  if (PixelRatio.get() < 3)
    return calculatedSize - 0.5
  return calculatedSize
};

Do refer Pixel Ratio as this allows you to better set up the function based on the device density.

Vinny answered 16/9, 2020 at 3:52 Comment(0)
C
0

I tried all PixelRatio.getFontScale() but this is worked well for me

const {width} = Dimensions.get('window')
console.log(width * 0.07)

This is the result when I run two different emulators

  • 1-25.200000000000003 - Nexus 5 API 25 Emulator
  • 2-27.490909090909096 - Pixel 3a API 25 Emulator
Creeper answered 3/7, 2023 at 15:20 Comment(0)
G
0
import { PixelRatio } from "react-native";

// Testing phone's pixel density as base
const basePixelDensity = 2.8125
const baseFontScale = 1.2

export const sp = (px: number) => {
  // the higher the font scaling the more we divided by it
  // the higher the pixel density compare to our base pixel density, the more we increase font size (or decrease if the pixel density is lower)
  return px / ((PixelRatio.getFontScale() / baseFontScale) * basePixelDensity) * (PixelRatio.get() / basePixelDensity);
};

Set your own base density and font scale, this worked for me wonderfully.

Gelsemium answered 18/3 at 0:53 Comment(0)
U
-6

You can use something like this.

var {height, width} = Dimensions.get('window'); var textFontSize = width * 0.03;

inputText: {
    color : TEXT_COLOR_PRIMARY,
    width: '80%',
    fontSize: textFontSize
}

Hope this helps without installing any third party libraries.

Underachieve answered 5/4, 2018 at 9:49 Comment(2)
and where 0.03 came from ?Hyperkeratosis
is it going to be responsive ?Concessionaire

© 2022 - 2024 — McMap. All rights reserved.