如果你是从 Web 前端转战 React Native (RN) 的开发者,第一次写布局时通常会产生三个灵魂拷问:
- "为什么我没写
display: flex,布局就已经生效了?" - "为什么元素默认是垂直排列的?我的
row去哪了?" - "官网文档里提到的 Yoga 到底是个什么东西?"
这篇文章将带你深入 React Native 的布局底层,揭开 Yoga 引擎 的面纱,并解析 RN 与 Web CSS 在布局上的核心差异。
一、幕后大脑:什么是 Yoga?
在 React Native 的官方文档中,你很难找到关于 Yoga 的详细篇幅,但它却是整个 RN 能够跨平台渲染 UI 的基石。
Yoga 是一个由 Facebook (Meta) 开发的跨平台布局引擎,使用 C++ 编写。
1. 为什么要造一个 Yoga?
React Native 的愿景是"Learn Once, Write Anywhere",但现实很骨感:
- iOS 原生使用的是 AutoLayout 或 Frame 计算。
- Android 原生使用的是 Measure/Layout 过程 (LinearLayout, RelativeLayout 等)。
- Web 使用的是 CSS Box Model。
如果 RN 想要跨平台,开发者不可能去写三套布局逻辑。于是 Facebook 决定统一使用 Flexbox 规范。但原生系统看不懂 Flexbox,这就需要一个"翻译官"。
2. Yoga 的工作流
Yoga 就是这个翻译官 ,也是 RN 的排版大脑:
- 输入: 你在 JS 代码里写的
flex: 1,width: 100等样式。 - 计算: RN 将这些指令传给 C++ 层的 Yoga,Yoga 根据 Flexbox 算法算出每个元素精确的
(x, y, width, height)。 - 输出: Yoga 将算好的坐标告诉 iOS 的
UIView或 Android 的ViewGroup,原生系统负责把它们画在屏幕上。
二、Web 开发者必读:RN 布局的"反直觉"差异
虽然 Yoga 实现了 Flexbox 规范,但为了适应移动端的特性和性能要求,它对标准 CSS 做了一些**"魔改"**。这也是新手最容易踩坑的地方。
1. 默认就是 display: flex
在 Web 中,div 默认是 display: block。但在 RN 中, "万物皆 Flex" 。
- 所有的组件(
View,Text,Image)默认都已经开启了 Flex 布局。 - 你不需要,也不能写
display: 'block'或display: 'grid'(RN 不支持 Grid,只能用 Flex 模拟)。
2. 主轴默认是纵向 (column)
这是最大的误解来源。
- Web CSS: 默认
flex-direction: row(从左到右)。 - React Native: 默认
flex-direction: column(从上到下)。
设计哲学: 手机屏幕是狭长的,用户习惯上下滑动浏览内容,因此将默认流设为从上到下更符合移动端直觉。如果你想横向排列按钮,必须显式声明:
JavaScript
<View style={{ flexDirection: 'row' }}>...</View>
3. 没有"样式继承" (Cascading)
CSS 全称是 Cascading Style Sheets (层叠样式表),但在 RN 中,样式不会继承。
- Web: 给父级设
color: red,子元素文字都会变红。 - RN: 给父
View设颜色,子Text毫无反应。你必须给每个Text单独设置样式。
4. 强制的 border-box
Web 开发中常需重置 box-sizing: border-box。在 RN 中,只有 border-box 这一种模式。Padding 和 Border 永远包含在宽高内,这大大简化了尺寸计算。
三、实战:彻底搞懂 flex: number
在 RN 中,我们经常看到 flex: 1 或 flex: 2,这比 Web CSS 中的 flex-grow/shrink/basis 组合要直观得多。
在 Yoga 引擎中,flex 接收一个数字,代表瓜分剩余空间的权重(比例)。
示例代码:
JavaScript
<View style={{ flex: 1, height: 300 }}>
{/* 红色:占 1 份 */}
<View style={{ flex: 1, backgroundColor: 'red' }} />
{/* 绿色:占 2 份 */}
<View style={{ flex: 2, backgroundColor: 'green' }} />
{/* 蓝色:占 3 份 */}
<View style={{ flex: 3, backgroundColor: 'blue' }} />
</View>
计算逻辑:
- 总份数 = 1 + 2 + 3 = 6 份。
- 红色高度 = 父容器高度 × (1/6)。
- 绿色高度 = 父容器高度 × (2/6)。
- 蓝色高度 = 父容器高度 × (3/6)。
注意: 只有当父容器有明确尺寸(固定高度 或 也是 flex: 1 撑开)时,子元素的 flex 比例瓜分才会生效。
四、总结与工具推荐
React Native 的布局系统可以总结为:一个用 C++ 编写的、默认纵向排列的、强制 border-box 的严格 Flexbox 子集。
调试利器:Yoga Playground
如果你在写复杂布局时被"挤"得乱七八糟,或者想单纯测试 Flexbox 逻辑,推荐使用官方的在线游乐场:
在这里,你可以脱离 RN 环境,直接调整 Flex 属性,实时观察布局引擎的计算结果。
核心对照表
| 特性 | Web CSS | React Native (Yoga) |
|---|---|---|
| 默认 Display | block |
flex |
| 默认主轴方向 | row (横向) |
column (纵向) |
| 盒模型 | content-box (默认) |
border-box (强制) |
| 样式继承 | 支持 | 不支持 |
| 单位 | px, rem, %, vw |
dp (逻辑点), % |
掌握了这些,你就掌握了 RN 布局的 90%。剩下的,就是把 Flexbox 的属性排列组合而已。