RN 的样式系统是 CSS 的子集 + 变体:基于 Flexbox 布局,但默认值、继承规则、支持的属性与 Web CSS 均有差异。核心原则是不要假设 Web 写法能直接移植,遇到问题优先查阅对应组件的官方文档确认属性是否受支持。
一、Flexbox 与 Web CSS 的差异
默认值
| 属性 | Web CSS | React Native |
|---|---|---|
flexDirection |
row |
column |
alignContent |
stretch |
flex-start |
flexShrink |
1 |
0 |
position |
static |
relative |
flex 简写
- Web 的
flex: 1等价于flex-grow: 1; flex-shrink: 1; flex-basis: 0。 - RN 底层由 Yoga 引擎计算,行为接近但边界情况与 W3C 规范略有出入,且不支持三值写法:
jsx
// ❌ RN 不支持
{ flex: '1 1 auto' }
// ✅ 分开声明
{ flexGrow: 1, flexShrink: 1, flexBasis: 'auto' }
不支持的属性 📢
floatdisplay: inline-flexflex-flow(需分别写flexDirection和flexWrap)grid系列属性
RN 特有属性
gap/rowGap/columnGap:RN 0.71+ 支持aspectRatio:接受数字(1)而非字符串("1/1")
常见陷阱 📢
子 View 若未声明尺寸或 flex,高度默认为 0,不可见:
jsx
// ❌ 子 View 高度为 0
<View style={{ flex: 1 }}>
<View style={{ backgroundColor: 'red' }} />
</View>
// ✅ 正确
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: 'red' }} />
</View>
二、样式系统规范
StyleSheet API
- RN 没有真正的 CSS,样式是 JavaScript 对象,属性名用 camelCase。
- 推荐用
StyleSheet.create()而非内联对象(样式会被 ID 化,减少跨线程传输开销):
jsx
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff' },
});
无 CSS 继承与选择器
RN 不支持 CSS 选择器,样式不会自动继承(Text 嵌套是例外:color、fontSize 等文字样式会从父 Text 继承):
jsx
// ❌ View 没有 color 属性,子 Text 不会继承
<View style={{ color: 'red' }}>
<Text>不会变红</Text>
</View>
// ✅ 每个组件单独设置
<Text style={{ color: 'red' }}>会变红</Text>
组件与样式绑定
不是所有属性对所有组件都有效:
| 组件 | 支持 | 不支持 |
|---|---|---|
View |
backgroundColor、border、shadow |
color、fontSize |
Text |
color、fontSize、fontWeight |
overflow: scroll |
Image |
width、height、resizeMode |
borderRadius(部分平台有问题) |
单位规则
jsx
// ✅ 无单位数字 = dp(与屏幕密度无关的像素)
{ width: 100, fontSize: 16 }
// ✅ 部分属性支持百分比字符串
{ width: '50%', height: '100%' }
// ❌ 不支持 px、rem 等单位
{ width: '100px', fontSize: '1rem' }
// ❌ 不支持 margin/padding 简写字符串
{ margin: '10 20' }
// ✅ 用 marginVertical / marginHorizontal
{ marginVertical: 10, marginHorizontal: 20 }
不支持的 CSS 功能
| CSS 功能 | RN 替代方案 |
|---|---|
::before / ::after |
额外的 View / Text 组件 |
:hover / :focus |
Pressable 的 onHoverIn / onPressIn |
transition / animation |
Animated API 或 react-native-reanimated |
box-shadow |
shadow*(iOS)+ elevation(Android) |
| 渐变背景 | expo-linear-gradient 等三方库 |
平台差异
jsx
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
box: {
shadowColor: '#000', // iOS 阴影
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
elevation: 5, // Android 阴影
},
});
// 按平台差异化样式
const textStyle = Platform.select({
ios: { fontSize: 14 },
android: { fontSize: 13 },
});
overflow 行为
Android 默认 hidden,iOS 默认 visible。需要裁剪内容时,应明确声明以避免平台差异:
jsx
{ overflow: 'hidden' }