# Flexbox 布局

Lynx 支持 CSS Flexbox 的常用能力，整体遵循 Flexbox 弹性分配模型。迁移 Web 布局时仍需关注默认布局、内在尺寸和默认值差异。

## 启用 Flex

```css
.container {
  display: flex;
}
```

## 常见布局模式

### 水平居中

```css
.center-horizontal {
  display: flex;
  flex-direction: row;
  justify-content: center; /* 主轴居中 */
}
```

### 垂直居中

```css
.center-vertical {
  display: flex;
  flex-direction: column;
  justify-content: center; /* 主轴居中 */
}
```

### 水平垂直居中

```css
.center-both {
  display: flex;
  justify-content: center; /* 主轴居中 */
  align-items: center; /* 交叉轴居中 */
}
```

```jsx
<view className="center-both">
  <text>Centered Content</text>
</view>
```

### 两端对齐

```css
.space-between {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
```

```jsx
<view className="space-between">
  <text>Left</text>
  <text>Right</text>
</view>
```

### 等分布局

```css
.equal-width {
  display: flex;
}

.equal-width .item {
  flex: 1; /* 每个 item 等分空间 */
}
```

### 左侧固定，右侧自适应

```css
.layout {
  display: flex;
}

.sidebar {
  width: 200px; /* 固定宽度 */
}

.main {
  flex: 1; /* 占据剩余空间 */
}
```

```jsx
<view className="layout">
  <view className="sidebar">
    <text>Sidebar</text>
  </view>
  <view className="main">
    <text>Main Content</text>
  </view>
</view>
```

### 底部固定按钮

```css
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.content {
  flex: 1; /* 内容区域占据剩余空间 */
}

.footer {
  /* 固定在底部 */
}
```

## Flex Wrap

```css
.wrap-container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.wrap-container .item {
  width: calc(50% - 8px); /* 两列布局 */
}
```

## 多行对齐

```css
.multi-line {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between; /* 多行之间的对齐 */
  gap: 16px;
}
```

## 属性值参考

### flex-direction

| 值               | 说明             |
| ---------------- | ---------------- |
| `row`            | 水平排列（默认） |
| `column`         | 垂直排列         |
| `row-reverse`    | 水平反向排列     |
| `column-reverse` | 垂直反向排列     |

### flex-wrap

| 值             | 说明           |
| -------------- | -------------- |
| `nowrap`       | 不换行（默认） |
| `wrap`         | 换行           |
| `wrap-reverse` | 反向换行       |

### flex-flow

`flex-direction` 和 `flex-wrap` 的简写属性。

```css
.container {
  flex-flow: row wrap; /* 等同于 flex-direction: row; flex-wrap: wrap; */
}
```

### justify-content

| 值              | 说明                        |
| --------------- | --------------------------- |
| `flex-start`    | 起点对齐                    |
| `center`        | 居中对齐                    |
| `flex-end`      | 终点对齐                    |
| `space-between` | 两端对齐，中间等分          |
| `space-around`  | 环绕对齐                    |
| `space-evenly`  | 均匀对齐                    |
| `stretch`       | 拉伸对齐（默认，Lynx 2.1+） |

### align-items

| 值           | 说明             |
| ------------ | ---------------- |
| `stretch`    | 拉伸填满（默认） |
| `flex-start` | 交叉轴起点对齐   |
| `center`     | 交叉轴居中对齐   |
| `flex-end`   | 交叉轴终点对齐   |
| `baseline`   | 基线对齐         |

### align-self

单个项目的对齐方式，覆盖容器的 `align-items`。

| 值           | 说明                 |
| ------------ | -------------------- |
| `auto`       | 继承自父元素（默认） |
| `stretch`    | 拉伸填满             |
| `flex-start` | 交叉轴起点对齐       |
| `center`     | 交叉轴居中对齐       |
| `flex-end`   | 交叉轴终点对齐       |
| `baseline`   | 基线对齐             |

### align-content

多行内容的对齐方式（需要 `flex-wrap: wrap`）。

| 值              | 说明             |
| --------------- | ---------------- |
| `stretch`       | 拉伸填满（默认） |
| `flex-start`    | 起点对齐         |
| `center`        | 居中对齐         |
| `flex-end`      | 终点对齐         |
| `space-between` | 两端对齐         |
| `space-around`  | 环绕对齐         |

### flex

`flex-grow`、`flex-shrink`、`flex-basis` 的简写。

```css
.item {
  flex: 1; /* 等同于 flex: 1 1 0% */
  flex: auto; /* 等同于 flex: 1 1 auto */
  flex: none; /* 等同于 flex: 0 0 auto */
}
```

### flex-grow

项目的放大比例，默认 `0`（不放大）。

### flex-shrink

项目的缩小比例，默认 `1`（可缩小）。

`flex-shrink` 只在主轴可用空间不足时生效：`flex-direction: row` 时看容器宽度，`flex-direction: column` 时看容器高度。如果父容器主轴尺寸没有被 `width` / `height`、`max-width` / `max-height`、外层约束或视口约束限制，子项总尺寸不会产生负剩余空间，也就不会触发压缩。不显式设置主轴尺寸通常可以避免压缩，但如果尺寸来自外层容器、视口或其它布局约束，仍可能触发 `flex-shrink`。

压缩量不是只按 `flex-shrink` 数值分配。当前 Lynx Flex 布局按缩放收缩因子分配负剩余空间：

```text
scaled shrink factor = flex-shrink * flex base size
```

`flex base size` 通常来自 `flex-basis`；当 `flex-basis: auto` 时，会使用主轴方向上的 `width` / `height` 或内容测量结果。也就是说，基础尺寸更大的项目即使 `flex-shrink` 相同，也会分摊更多压缩量。

示例：父容器宽度为 `500px`，两个子项总基础宽度为 `600px`，需要压缩 `100px`。

```css
.item-a {
  width: 200px;
  flex-shrink: 1;
}

.item-b {
  width: 400px;
  flex-shrink: 2;
}
```

`item-a` 的收缩权重是 `200 * 1 = 200`，`item-b` 的收缩权重是 `400 * 2 = 800`。最终 `item-a` 压缩 `20px`，宽度为 `180px`；`item-b` 压缩 `80px`，宽度为 `320px`。

如果多个项目的基础尺寸相同，看起来会像只按 `flex-shrink` 数值等比压缩；一旦基础尺寸不同，基础尺寸也会参与分配。

### flex-basis

项目在分配多余空间之前的初始大小，默认 `auto`。

```css
.item {
  flex-basis: 100px; /* 固定大小 */
  flex-basis: auto; /* 根据内容大小 */
}
```

### order

项目的排列顺序，默认 `0`。数值越小，排列越靠前。

```css
.item:first-child {
  order: -1; /* 排到最前面 */
}
```

### gap / row-gap / column-gap

项目之间的间距。

```css
.container {
  gap: 16px; /* 行和列间距都是16px */
  row-gap: 8px; /* 行间距8px */
  column-gap: 12px; /* 列间距12px */
}
```

## 注意事项

1. **min-content 不支持**: `flex-basis: min-content` 会被视为 0px

   ```css
   /* ❌ 不支持 */
   .item {
     flex-basis: min-content;
   }

   /* ✅ 替代方案 */
   .item {
     flex-basis: auto;
   }
   ```

2. **Text 组件**: Flex 子元素如果是 Text，可能需要设置 `white-space: nowrap` 防止换行

   ```css
   .flex-item-text {
     white-space: nowrap;
   }
   ```

3. **内容不会自动形成 Web 式收缩下限**: Lynx 的 `flex-shrink` 不会套用 Web flex item 的 `min-content` / auto minimum size 保护。空间不足时，包含 Text、图片或嵌套子节点等内容的 flex item 也可能继续沿主轴被压缩；Web 则可能因为内容形成默认最小宽度或最小高度而不继续收缩。可以把 Lynx 的默认表现理解为 Web flex item 在主轴方向显式设置最小值为 `0`。需要固定尺寸或保护内容的项目请设置 `flex-shrink: 0`，或显式设置主轴方向的 `min-width` / `min-height`。需要 Web 预览页对齐 Lynx 压缩行为时，通常要在 Web 侧设置 `min-width: 0`（row 方向）或 `min-height: 0`（column 方向）。

4. **justify-content 默认值**: Lynx 中 `justify-content` 默认值为 `stretch`（Web 中默认为 `flex-start`）
