Card 卡片

承载一组内容的容器,比页面底色高出一层。

サクラノ詩

连载中

转学第一天,我在天台遇见了那个抱着旧相机的少女。

全 12 卷

import { Button, Card, Divider, Heading, Inline, Stack, Tag, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Card className="w-full max-w-sm">
      <Stack>
        <Stack gap="xs">
          <Inline justify="between" align="start" wrap={false}>
            <Heading level={3} size="md">
              サクラノ詩
            </Heading>
            <Tag tone="success">连载中</Tag>
          </Inline>
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </Stack>
        <Divider />
        <Inline justify="between">
          <Text tone="faint" size="sm">
            全 12 卷
          </Text>
          <Button variant="ghost" tone="neutral" size="sm">
            查看
          </Button>
        </Inline>
      </Stack>
    </Card>
  )
}
tsx

用法

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

卡片由三部分构成视觉:自身的背景色、一条细边框,以及一层静止状态的阴影,三者共同使它比页面底色高出一层。内容置于 children 中。

卡片自带背景色、一条细边框与一层阴影,内容置于默认插槽中。

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

export default function Demo() {
  return (
    <Card className="w-full max-w-sm">
      <Text>卡片自带背景色、一条细边框与一层阴影,内容置于默认插槽中。</Text>
    </Card>
  )
}
tsx

卡片只负责这一层容器,不决定其中内容如何排布。内容的方向与间距应交由 Stack、Inline 等布局组件处理。

示例

内边距

卡片默认带有内边距,取值随密度变化。图片、表格等需要贴合卡片边缘的内容,应将 padded 设为 false,再由内部容器提供内边距。此时卡片会裁去溢出的部分,贴边内容的直角不会盖住卡片的圆角。

夏日午后的坡道

通向车站的那条坡道

图片贴合卡片边缘,内边距改由内部容器提供。

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

export default function Demo() {
  return (
    <Card padded={false} className="w-full max-w-sm overflow-hidden">
      <Image src="/sample.webp" alt="夏日午后的坡道" className="h-32 w-full" />
      <Stack gap="xs" className="p-[var(--hn-panel-p)]">
        <Heading level={3} size="base">
          通向车站的那条坡道
        </Heading>
        <Text tone="muted" size="sm">
          图片贴合卡片边缘,内边距改由内部容器提供。
        </Text>
      </Stack>
    </Card>
  )
}
tsx

若内容需要随圆角一同裁切,为卡片添加 overflow-hidden。

语义标签

as 用于指定渲染的标签,默认为 div,仅在需要更准确的语义时替换:独立成篇的内容使用 article,页面中的一个区块使用 section;一组卡片构成列表时,容器使用 ul,每张卡片使用 li。

独立成篇、可单独发布的内容使用 article

页面中的一个区块使用 section

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

export default function Demo() {
  return (
    <Stack className="w-full max-w-sm">
      <Card as="article">
        <Text>独立成篇、可单独发布的内容使用 article</Text>
      </Card>
      <Card as="section">
        <Text>页面中的一个区块使用 section</Text>
      </Card>
    </Stack>
  )
}
tsx

可点击的卡片

卡片自身不带任何可点击的样式,既不会在悬停时改变颜色,也不会提升阴影层级。需要整张卡片可点击时,由调用方组合实现:as="button" 替换标签,hn-interactive 提供指针样式与焦点环,hn-state-layer 提供悬停时的状态层,hn-press-lg 将按压时的缩放幅度调整为适合大面积元素的档位,另置入一个 Ripple。

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

export default function Demo() {
  return (
    <Card
      as="button"
      className="hn-interactive hn-state-layer hn-press-lg w-full max-w-sm text-start"
    >
      <Ripple />
      <Stack gap="xs">
        <Heading level={3} size="base">
          整张卡片都是可点击区域
        </Heading>
        <Text tone="muted" size="sm">
          悬停时的状态层与按下时的波纹均由调用方添加。
        </Text>
      </Stack>
    </Card>
  )
}
tsx

若卡片中仅有局部可点击,则不应如此处理:应在该处放置 Button 或 Link,卡片本身保持静态。

密度

内边距取自密度 token,因此在任意祖先元素上设置 data-density="compact",其范围内的卡片都会随之收紧,无需向卡片传入参数。

comfortable

内边距 20px

compact

内边距 14px

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

export default function Demo() {
  return (
    <Inline align="start" className="w-full max-w-lg">
      <Card className="flex-1">
        <Stack gap="xs">
          <Text size="sm" tone="faint">
            comfortable
          </Text>
          <Text>内边距 20px</Text>
        </Stack>
      </Card>
      <Card data-density="compact" className="flex-1">
        <Stack gap="xs">
          <Text size="sm" tone="faint">
            compact
          </Text>
          <Text>内边距 14px</Text>
        </Stack>
      </Card>
    </Inline>
  )
}
tsx

无障碍

  • 卡片默认渲染为 div,不带角色,屏幕阅读器按普通内容朗读。
  • 整张卡片可点击时必须替换为 button 或链接。不应为 div 绑定点击事件,那样键盘无法触达,屏幕阅读器也无法识别其为控件。
  • 卡片内的标题使用 Heading,并选择恰当的 level,使其衔接页面已有的标题层级。

API

Props

属性
类型
默认值
说明
padded
boolean
true
是否带内边距,取值随密度变化;关闭时裁去溢出
as
string
'div'
渲染的标签
asChild
boolean
false
不渲染自身标签,把样式合并到唯一的子元素
className
string
—
追加至根元素的类名

内容属性

属性
说明
children
卡片的内容