Flex 弹性布局

完整控制方向、对齐与分布的 flex 容器。

ATRI

科幻连载中
import { Button, Card, Flex, Heading, Tag } from '@hina-ui/react'

export default function Demo() {
  return (
    <Card className="w-full max-w-lg">
      <Flex justify="between" align="center" wrap className="gap-3">
        <Flex direction="col" gap="xs">
          <Heading level={3} size="md">
            ATRI
          </Heading>
          <Flex gap="xs">
            <Tag>科幻</Tag>
            <Tag>连载中</Tag>
          </Flex>
        </Flex>
        <Flex gap="sm">
          <Button variant="soft" tone="neutral">
            加入书架
          </Button>
          <Button>开始阅读</Button>
        </Flex>
      </Flex>
    </Card>
  )
}
tsx

用法

import { Flex } from '@hina-ui/react'
ts

Flex 开放了 flex 布局的四个属性:direction、align、justify 和 wrap。方向固定时用 Stack 或 Inline 更简洁,需要切换方向或完整控制对齐时用 Flex。

import { Card, Flex } from '@hina-ui/react'

export default function Demo() {
  return (
    <Flex gap="sm">
      <Card className="bg-inset size-10" padded={false} />
      <Card className="bg-inset size-10" padded={false} />
      <Card className="bg-inset size-10" padded={false} />
    </Flex>
  )
}
tsx

示例

方向

direction 有四个取值,默认横排。

row

1
2
3

row-reverse

1
2
3

col

1
2
3

col-reverse

1
2
3
import { Card, Flex, Stack, Text } from '@hina-ui/react'

const directions = ['row', 'row-reverse', 'col', 'col-reverse'] as const

export default function Demo() {
  return (
    <Flex gap="lg" wrap>
      {directions.map(direction => (
        <Stack key={direction} gap="xs">
          <Text tone="muted" size="sm">
            {direction}
          </Text>
          <Flex direction={direction} gap="sm" className="bg-inset rounded-md p-3">
            <Card className="bg-surface grid size-8 place-items-center text-sm" padded={false}>
              1
            </Card>
            <Card className="bg-surface grid size-8 place-items-center text-sm" padded={false}>
              2
            </Card>
            <Card className="bg-surface grid size-8 place-items-center text-sm" padded={false}>
              3
            </Card>
          </Flex>
        </Stack>
      ))}
    </Flex>
  )
}
tsx

间距

gap 只接受档位。md 档随方向取值:横排取 --hn-inline-gap,纵排取 --hn-stack-gap,因此方向变化时无需调整间距。其余档位在两个方向上一致,分别是 0、4、8、24 和 32 像素。

横向的 md 档取 12 像素

纵向的 md 档取 16 像素

import { Card, Flex, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Flex gap="xl" wrap>
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          横向的 md 档取 12 像素
        </Text>
        <Flex gap="md" className="bg-inset rounded-md p-3">
          <Card className="bg-surface size-8" padded={false} />
          <Card className="bg-surface size-8" padded={false} />
          <Card className="bg-surface size-8" padded={false} />
        </Flex>
      </Stack>
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          纵向的 md 档取 16 像素
        </Text>
        <Flex direction="col" gap="md" className="bg-inset rounded-md p-3">
          <Card className="bg-surface size-8" padded={false} />
          <Card className="bg-surface size-8" padded={false} />
          <Card className="bg-surface size-8" padded={false} />
        </Flex>
      </Stack>
    </Flex>
  )
}
tsx

对齐与分布

align 控制交叉轴,justify 控制主轴。横排时 align 作用于纵向、justify 作用于横向,纵排时两者对调。

align 管交叉轴

start

center

end

stretch

justify 管主轴

import { Card, Flex, Stack, Text } from '@hina-ui/react'

const aligns = ['start', 'center', 'end', 'stretch'] as const
const justifies = ['start', 'center', 'end', 'between'] as const

export default function Demo() {
  return (
    <Stack>
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          align 管交叉轴
        </Text>
        <Flex gap="lg" wrap>
          {aligns.map(align => (
            <Stack key={align} gap="xs">
              <Text tone="muted" size="sm">
                {align}
              </Text>
              <Flex align={align} gap="sm" className="bg-inset h-24 rounded-md p-3">
                <Card className="bg-surface h-8 w-8" padded={false} />
                <Card className="bg-surface h-12 w-8" padded={false} />
              </Flex>
            </Stack>
          ))}
        </Flex>
      </Stack>
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          justify 管主轴
        </Text>
        <Flex direction="col" gap="sm">
          {justifies.map(justify => (
            <Flex key={justify} justify={justify} className="bg-inset w-64 rounded-md p-3">
              <Card className="bg-surface size-8" padded={false} />
              <Card className="bg-surface size-8" padded={false} />
            </Flex>
          ))}
        </Flex>
      </Stack>
    </Stack>
  )
}
tsx

换行

不设置 wrap 时不换行,这是 flex 自身的行为。Inline 默认换行,Flex 则不默认换行。

wrap 为真时换行

默认不换行,保持在一行

import { Card, Flex, Stack, Text } from '@hina-ui/react'

const items = Array.from({ length: 10 }, (_, i) => i + 1)

export default function Demo() {
  return (
    <Stack className="w-full max-w-xs">
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          wrap 为真时换行
        </Text>
        <Flex wrap gap="sm">
          {items.map(i => (
            <Card key={i} className="bg-inset size-10" padded={false} />
          ))}
        </Flex>
      </Stack>
      <Stack gap="xs">
        <Text tone="muted" size="sm">
          默认不换行,保持在一行
        </Text>
        <Flex gap="sm" className="overflow-hidden">
          {items.map(i => (
            <Card key={i} className="bg-inset size-10 shrink-0" padded={false} />
          ))}
        </Flex>
      </Stack>
    </Stack>
  )
}
tsx

随断点变化

方向与对齐在不同断点下不同时,用 Tailwind 的断点类覆盖,例如 sm:flex-row。属性本身不接受响应式对象。

ATRI

窄屏时封面在上、文字在下,宽屏时并排。断点用 Tailwind 的类覆盖 direction。

import { Card, Flex, Heading, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Flex direction="col" gap="md" className="w-full max-w-lg sm:flex-row sm:items-center">
      <Card className="bg-inset h-24 shrink-0 sm:w-32" padded={false} />
      <Flex direction="col" gap="xs">
        <Heading level={3} size="md">
          ATRI
        </Heading>
        <Text tone="muted" size="sm">
          窄屏时封面在上、文字在下,宽屏时并排。断点用 Tailwind 的类覆盖 direction。
        </Text>
      </Flex>
    </Flex>
  )
}
tsx

根元素

as 接受标签名或组件,例如 as="section" 或 next/link 的 as={Link}。布局类名、额外属性、事件处理函数和 children 会传给该组件,不增加包裹层;自定义组件需将 className 等属性传到实际渲染的根元素。

API

属性
类型
默认值
说明
direction
'row' | 'col' | 'row-reverse' | 'col-reverse'
'row'
主轴方向
gap
'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
—
子元素之间的间距
align
'start' | 'center' | 'end' | 'baseline' | 'stretch'
—
交叉轴对齐方式
justify
'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'
—
主轴分布方式
wrap
boolean
—
放不下时是否换行
as
string | Component
'div'
渲染的标签或 React 组件
className
string
—
追加至容器的类名
属性
说明
children
子元素