React Native Extended StyleSheet
Drop-in replacement of React Native StyleSheet with media-queries, variables, dynamic themes, relative units, percents, math operations, scaling and other styling stuff.
Installation
npm i react-native-extended-stylesheet --save
Usage
- Import
EStyleSheet
and callEStyleSheet.build()
in entry point of your app:
// app.js; EStyleSheet;
- Define styles using
EStyleSheet.create()
in components:
// component.js; const styles = EStyleSheet; Component { return // use styles as normal react-native StyleSheet <View style=stylescolumn> <Text style=stylestext>Hello</Text> </View> ; }
[top]
Features
Global variables
Global variables are useful for global theming or A/B testing of your app.
They are passed to EStyleSheet.build()
and available in any stylesheet.
// app entry: set global variables and calc stylesEStyleSheet; // component: use global variablesconst styles = EStyleSheet;
[top]
Theming
There can be two types of themes:
- static (app reload needed to theme change)
- dynamic (theme can be changed in runtime)
Please see examples of static themes and dynamic themes.
[top]
Local variables
Local variables can be defined directly in sylesheet and have priority over global variables.
To define local variable just start it with $
:
const styles = EStyleSheet;
Local variables are also available in result style: styles.$textColor
.
[top]
Math operations
Any value can contain one of following math operations: *
, /
, +
, -
. Operands can be numbers, variables and percents.
For example, to render circle you may create style:
const styles = EStyleSheet;
[top]
REM units
Similar to CSS3 rem unit it allows to define any integer value as relative to the root element. In our case root value is special rem
global variable that can be set in EStyleSheet.build()
. It makes easy to scale app depending on screen size and other conditions. Default rem is 16
.
// componentconst styles = EStyleSheet;// app entrylet height width = Dimensions;EStyleSheet;
[top]
Percents
Percent values are supported natively since React Native 0.43.
Style properties that contain only percent value (e.g. "80%"
) are passed as is to the native code.
The only case when JavaScript calculation is applied by this library - operations with percent values, e.g. "100% - 20"
.
Percents are calculated relative to screen width/height on application launch.
const styles = EStyleSheet;
Percents in nested components
If you need sub-components with percent operations - you can use variables.
For example, to render 2 sub-columns with 30%/70% width of parent:
{ return <View style=stylescolumn> <View style=stylessubColumnLeft></View> <View style=stylessubColumnRight></View> </View> ;} ... const styles = EStyleSheet;
[top]
Media queries
Media queries allows to have different styles for different screens, platform and orienation.
They are supported as properties with @media
prefix (thanks for idea to @grabbou,
#5).
Media queries can operate with the following values:
- media type:
ios|android
width
,min-width
,max-width
height
,min-height
,max-height
orientation
(landscape|portrait
)aspect-ratio
Example:
const styles = EStyleSheet;
Also you can use media queries on style level:
const styles = EStyleSheet;
Scaling
You can apply scale to components by setting special $scale
variable.
const styles = EStyleSheet;
This helps to create reusable components that could be scaled depending on prop:
Component static propTypes = scale: ReactPropTypesnumber ; { let style = return <View style=stylebutton> </View> ; } let { return EStyleSheet;}
To cache calculated styles please have a look on caching section.
[top]
Underscored styles
Original react-native stylesheets are calculated to integer numbers and original values are unavailable.
But sometimes they are needed. Let's take an example:
You want to render text and icon with the same size and color.
You can take this awesome icon library
and see that <Icon>
component has size
and color
props.
It would be convenient to define style for text and keep icon's size/color in sync.
const styles = EStyleSheet;
In runtime styles
created with original react's StyleSheet
will look like:
styles = text: 0
But extended stylesheet saves calculated values under _text
property:
styles = text: 0 _text: fontSize: 16 color: 'gray'
To render icon we just take styles from _text
:
return <View> <Icon name="rocket" size=styles_textfontSize color=styles_textcolor /> <Text style=stylestext>Hello</Text> </View>;
[top]
Pseudo classes (:nth-child)
Extended stylesheet supports 4 pseudo classes: :first-child
, :nth-child-even
, :nth-child-odd
, :last-child
. As well as in traditional CSS it allows to apply special styling for first/last items or render stripped rows.
To get style for appropriate index you should use EStyleSheet.child()
method.
It's signature: EStyleSheet.child(stylesObj, styleName, index, count)
.
const styles = EStyleSheet;... { return <View> items </View> ;}
[top]
Value as a function
For the deepest customization you can specify any value as a function that will be executed on EStyleSheet build. For example, you may darken or lighten color of variable via npm color package:
;; const styles = EStyleSheet;... { return <TouchableHighlight style=stylesbutton underlayColor=styles$underlayColor> ... </TouchableHighlight> ;}
[top]
Caching
If you use dynamic styles depending on runtime prop or you are making reusable component with dynamic styling
you may need stylesheet creation in every render()
call. Let's take example from scaling section:
Component static propTypes = scale: ReactPropTypesnumber ; { let style = return <View style=stylebutton> </View> ; } let { return EStyleSheet;}
To avoid creating styles on every render you can use EStyleSheet.memoize()
wrapper method that works similar to lodash.memoize: store result for particular parameters and returns it from cache when called with the same parameters. Updated example:
let getStyle = EStyleSheet;
Now if you call getStyle(1.5)
3 times actually style will be created on the first call
and two other calls will get it from cache.
[top]
Outline for debug
To outline all components for debug purpuses just set special $outline
variable:
// outline all stylesheetsEStyleSheet; // outline particular stylesheetconst styles = EStyleSheet;
[top]
EStyleSheet API
.create()
/** * Creates extended stylesheet object * * @param * @returns */ {...}
[top]
.build()
/** * Calculates all stylesheets * * @param */ {...}
[top]
.value()
/** * Calculates particular value * * @param * @param * @returns */ {...}
[top]
.memoize()
/** * Wraps function to cache calls with the same parameters * * @param * @returns */ {...}
[top]
.child()
/** * Returns styles with pseudo classes :first-child, :nth-child-even, :last-child according to index and count * * @param * @param * @param * @param * @returns */ {...}
[top]
.subscribe()
/** * Subscribe to events. Currently only 'build' event is supported * * @param * @param */ {...}
This method is useful when you want to pre-render some component on init.
As extended style is calculated after call of EStyleSheet.build()
,
it is not available instantly after creation so you should wrap pre-render
info listener to build
event:
const styles = EStyleSheet; // this will NOT work as styles.button is not calculated yetlet Button = <View style=stylesbutton></View>; // but this will worklet Button;EStyleSheet;
[top]
FAQ
What about orientation change?
Currently orientation change is not properly supported. Please see
this issue for more details.
Changelog
Feedback
If you have any ideas or something goes wrong feel free to open new issue.
License
MIT
[top]