AspectRatio

Holds its content to a given width-to-height ratio.

ATRI

ATRI

Covers are cropped to 3:4, so originals of any size line up.

<script setup lang="ts">
  import { AspectRatio, Card, Image, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Card class="w-full max-w-xs" :padded="false">
    <AspectRatio :ratio="3 / 4" class="overflow-hidden rounded-t-lg">
      <Image src="/sample.webp" alt="ATRI" class="size-full" />
    </AspectRatio>
    <Stack gap="xs" class="p-4">
      <Text class="font-medium">ATRI</Text>
      <Text tone="muted" size="sm">
        Covers are cropped to 3:4, so originals of any size line up.
      </Text>
    </Stack>
  </Card>
</template>
vue

Usage

import { AspectRatio } from '@hina-ui/vue'
ts

ratio is the width divided by the height and defaults to 16 / 9. The height follows from the width and that ratio, so images of any size end up in a frame of the same shape.

A slope on a summer afternoon
<script setup lang="ts">
  import { AspectRatio, Image } from '@hina-ui/vue'
</script>

<template>
  <AspectRatio class="bg-inset w-full max-w-md overflow-hidden rounded-md">
    <Image src="/sample.webp" alt="A slope on a summer afternoon" class="size-full" />
  </AspectRatio>
</template>
vue

Examples

Common ratios

A division reads better than a decimal: :ratio="3 / 4".

1 / 1

A slope on a summer afternoon

4 / 3

A slope on a summer afternoon

16 / 9

A slope on a summer afternoon

3 / 4

A slope on a summer afternoon
<script setup lang="ts">
  import { AspectRatio, Image, Inline, Stack, Text } from '@hina-ui/vue'

  const ratios = [
    { label: '1 / 1', value: 1 },
    { label: '4 / 3', value: 4 / 3 },
    { label: '16 / 9', value: 16 / 9 },
    { label: '3 / 4', value: 3 / 4 },
  ]
</script>

<template>
  <Inline align="start" class="gap-4">
    <Stack v-for="ratio in ratios" :key="ratio.label" gap="xs" class="w-32">
      <Text tone="muted" size="sm">{{ ratio.label }}</Text>
      <AspectRatio :ratio="ratio.value" class="bg-inset overflow-hidden rounded-md">
        <Image src="/sample.webp" alt="A slope on a summer afternoon" class="size-full" />
      </AspectRatio>
    </Stack>
  </Inline>
</template>
vue

Embedded content

Whatever sits inside fills the frame. Images and videos are already set to object-fit: cover, filling the frame and cropping the excess; an iframe and the like simply stretch to fit.

An iframe or video goes here and fills the whole frame

<script setup lang="ts">
  import { AspectRatio, Center, Text } from '@hina-ui/vue'
</script>

<template>
  <AspectRatio class="bg-inset w-full max-w-md overflow-hidden rounded-md">
    <Center class="size-full">
      <Text tone="muted" size="sm">An iframe or video goes here and fills the whole frame</Text>
    </Center>
  </AspectRatio>
</template>
vue

API

Prop
Type
Default
Description
ratio
number
16 / 9
Width divided by height
class
string
—
Classes appended to the outer element
Slot
Description
default
The content in the frame